<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Praise Idowu</title>
    <description>The latest articles on DEV Community by Praise Idowu (@praise002).</description>
    <link>https://dev.to/praise002</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1149307%2F4f464fd1-411b-4914-a2d1-0fb5fef4fcd3.jpg</url>
      <title>DEV Community: Praise Idowu</title>
      <link>https://dev.to/praise002</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/praise002"/>
    <language>en</language>
    <item>
      <title>Hacktoberfest 2024: My Contributor Experience</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Thu, 31 Oct 2024 20:32:36 +0000</pubDate>
      <link>https://dev.to/praise002/hacktoberfest-2024-my-contributor-experience-4mf1</link>
      <guid>https://dev.to/praise002/hacktoberfest-2024-my-contributor-experience-4mf1</guid>
      <description>&lt;p&gt;Hi, my name is Praise. I began coding in 2022, starting out as a Backend Developer, and I’m now exploring full-stack development and AI. Last year, I also ventured into technical writing, fueled by my love for teaching and guiding others on their learning paths. For me, every bit of knowledge I gain is something I want to share, because I believe in helping others grow.&lt;/p&gt;

&lt;p&gt;I’ve always been curious about contributing to open-source. My first contribution was last year after digesting a lot of materials online, which led me to tackle a good first issue. That experience helped me get familiar with collaborative Git commands that I wouldn’t normally use. However, during last year’s Hacktoberfest, I felt overwhelmed after browsing several codebases and decided not to proceed.&lt;/p&gt;

&lt;p&gt;Fast forward to this year, I came across a video by "&lt;a href="https://www.youtube.com/@btcwso" rel="noopener noreferrer"&gt;Beyond the Classroom&lt;/a&gt;," titled "&lt;a href="https://youtu.be/p_iTnCE9WSI?si=DTZ3QaPiOlp85vnz" rel="noopener noreferrer"&gt;Open-source stories&lt;/a&gt;" where students who contributed to open-source were interviewed. I watched the video and felt inspired to try again. I opened GitHub and began searching for projects. This time, I wanted to start with documentation or writing contributions instead of code, but once again, I felt overwhelmed.&lt;/p&gt;

&lt;p&gt;As a member of the She Code Africa (SCA) community, I found out that they had partnered with Made in Nigeria for Hertoberfest, an open-source initiative. I didn’t hesitate to apply, and I was accepted. However, when I tried joining a team, I struggled as most were already full by the time I expressed interest. I felt discouraged and decided to give up.&lt;/p&gt;

&lt;p&gt;Then, an unexpected opportunity came. A participant from the "Beyond the Classroom" video posted about an open-source project on her &lt;a href="https://www.linkedin.com/posts/mercy-umoh_hacktoberfest-womenintech-opensource-activity-7250405823686860800-S3GG?utm_source=share&amp;amp;utm_medium=member_desktop" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. It was an Hertoberfest project titled &lt;a href="https://github.com/SCA-OAU/LearnLink" rel="noopener noreferrer"&gt;LearnLink&lt;/a&gt;. I immediately messaged her and expressed my interest in contributing. Interestingly, I had a similar idea for a project like LearnLink last year, but I wasn’t confident enough to build it on my own.&lt;/p&gt;

&lt;p&gt;The project resonated with me because people often reach out for guidance and resources, and since I’m focused on web development, I frequently have to connect them with people from other fields. Contributing to LearnLink felt like a natural fit. I focused on the backend and AI tracks, with 98% of my contributions being in the backend.&lt;/p&gt;

&lt;p&gt;Beyond Hacktoberfest, I would love to expand the LearnLink project by adding additional tracks and resources to help guide learners in their journeys.&lt;/p&gt;

&lt;p&gt;One of the biggest lessons I learned from this experience is the importance of seizing opportunities. It has also given me the confidence to take on larger challenges and contribute to bigger projects, as well as improve the software I regularly use. I have a goal of participating in the Google Season of Docs (GSOD) someday, and with this first step, I’m confident I will achieve that.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hacktoberfest</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Memory</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Sun, 03 Mar 2024 14:43:38 +0000</pubDate>
      <link>https://dev.to/praise002/memory-4g6c</link>
      <guid>https://dev.to/praise002/memory-4g6c</guid>
      <description>&lt;p&gt;This article continues our series on Data Structures and Algorithms (DSA). So far, you have likely written "working" and "non-working" code while learning elementary programming. While the concepts apply similarly to JavaScript, we will focus on Python in this article.&lt;/p&gt;

&lt;p&gt;Maybe you wrote messy code that "got the job done," littered it with print() statements, or even debugged it manually. However, if you understand how your code works in memory, you will go back to optimize this "messy" code.&lt;/p&gt;

&lt;p&gt;There are two mechanisms for storing data on your computer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage&lt;/strong&gt;: This includes devices like flash drives and hard disks. Data stored here is permanent, meaning it persists even after turning your computer off and back on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory&lt;/strong&gt;: Also known as RAM (Random Access Memory). Data stored on it is temporary, which means it disappears once you turn off your computer or exit the application.&lt;/p&gt;

&lt;p&gt;Given that storage can hold data permanently, why use memory? The answer lies in speed. Accessing data from storage is much slower than accessing it from memory. So, when you need to use data, it gets temporarily copied to memory for faster processing. Once you are done, you can save it back to storage for long-term retention.&lt;/p&gt;

&lt;p&gt;To understand this better, let's take a look at the types of memory.&lt;/p&gt;

&lt;p&gt;Computers have two types of memory:&lt;br&gt;
&lt;strong&gt;Short-term memory&lt;/strong&gt;: Used for immediate tasks.&lt;br&gt;
&lt;strong&gt;Long-term memory&lt;/strong&gt;: Used for storing data, this memory serves as a more permanent storage.&lt;/p&gt;

&lt;p&gt;When you run a program, your CPU allocates a portion of short-term memory to execute its instructions.&lt;/p&gt;

&lt;p&gt;To see memory in action, open your Task Manager and launch applications like Chrome. Observe that memory usage increases as you open more apps. This increased usage eventually slows down your computer. To improve performance, close some applications to free up memory space.&lt;/p&gt;

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

&lt;p&gt;Why do we need to learn Memory?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To use the memory optimally.&lt;/li&gt;
&lt;li&gt;To make the right decision when writing code. It's either speed or space preference, depending on what you are ready to forgo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Memory Hierarchy
&lt;/h2&gt;

&lt;p&gt;Every computer relies on a layered system called the memory hierarchy to manage data storage and access. This system balances speed, cost, and capacity by using different memory types with distinct characteristics. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Registers &amp;amp; Cache:&lt;/strong&gt;&lt;br&gt;
These two memories reside on the CPU itself.&lt;/p&gt;

&lt;p&gt;Registers are the fastest areas of memory on the CPU, but they are also the smallest. They store data that is required immediately.&lt;/p&gt;

&lt;p&gt;The cache is an area of memory on the CPU that is used to store the next instructions that need to be executed. They are slower compared to registers. It stores data that is required shortly. There are further levels within the hierarchy, like L1, L2, and L3 cache, for varying speeds and sizes.&lt;br&gt;
L1 - fastest but smallest&lt;br&gt;
L2 - slower but bigger&lt;br&gt;
L3 - slowest but biggest&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main Memory (RAM):&lt;/strong&gt;&lt;br&gt;
The main memory is the primary working memory of your computer. It holds data and instructions currently being used by programs. Main memory is faster than secondary storage but volatile: meaning data vanishes when you power it off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondary Storage (Hard Drives, SSDs):&lt;/strong&gt;&lt;br&gt;
This is a persistent storage that retains data even after power is off. Slower than RAM but much more affordable and larger. It is ideal for long-term data archiving and accessing less frequently used information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network-based Storage:&lt;/strong&gt;&lt;br&gt;
This storage is located on external servers accessed through networks. Offers flexibility and scalability for sharing data among multiple users and devices. It can be slower than local storage but offers remote access benefits.&lt;/p&gt;
&lt;h2&gt;
  
  
  Measuring Space
&lt;/h2&gt;

&lt;p&gt;Have you ever wondered how the computer stores all the information you use? To understand how computers represent data, it is crucial to first grasp the decimal system.&lt;/p&gt;
&lt;h3&gt;
  
  
  Understanding the Decimal system
&lt;/h3&gt;

&lt;p&gt;You are likely already familiar with the &lt;strong&gt;decimal system&lt;/strong&gt;, also known as base-10. This decimal system uses ten digits (0-9) to represent numbers, where each digit's position holds a specific weight based on powers of 10. For instance, in the number 123, the "1" represents 1 x 10&lt;sup&gt;2&lt;/sup&gt; (100), the "2" represents 2 x 10&lt;sup&gt;1&lt;/sup&gt; (20), and the "3" represents 3 x 10&lt;sup&gt;0&lt;/sup&gt; (1).&lt;/p&gt;
&lt;h3&gt;
  
  
  The Binary System
&lt;/h3&gt;

&lt;p&gt;Computers primarily rely on the &lt;strong&gt;binary system(bit)&lt;/strong&gt;. This base-2 system is composed of only two digits: 0 and 1. These digits symbolize different states, often likened to electrical switches, where 0 represents "off" and 1 represents "on."&lt;/p&gt;
&lt;h3&gt;
  
  
  Bits
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;bit&lt;/strong&gt; (short for &lt;strong&gt;binary digit&lt;/strong&gt; and denoted by &lt;strong&gt;b&lt;/strong&gt;) is the basic unit to measure data in a computer. It can only hold one value at a time, either &lt;strong&gt;0&lt;/strong&gt; or &lt;strong&gt;1&lt;/strong&gt;. Just like a single switch can only be on or off.&lt;/p&gt;
&lt;h3&gt;
  
  
  Nibbles
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;nibble&lt;/strong&gt; (or &lt;strong&gt;half-byte&lt;/strong&gt;) comprises four bits (4 bits). This grouping of bits allows for efficient representation of certain data types, such as storing a single hexadecimal digit (0-F), which requires four bits.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bytes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;byte&lt;/strong&gt; (denoted by &lt;strong&gt;B&lt;/strong&gt;), consisting of eight bits (8 bits), is the standard unit for measuring computer memory and storage capacity. Most modern character encodings, like &lt;a href="https://en.wikipedia.org/wiki/ASCII" rel="noopener noreferrer"&gt;ASCII&lt;/a&gt;, assign one byte to represent a single character. For example, the ASCII encoding of letter 'A' is represented as 01000001. You can view the ASCII chart by clicking &lt;a href="https://www.ascii-code.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Unit of measurement
&lt;/h3&gt;

&lt;p&gt;While bytes are the fundamental unit, larger storage capacities utilize prefixes like kilo (103), mega (106), giga (109), and tera (1012) to represent multiples of bytes. For example, a kilobyte (KB) is equivalent to 1000 bytes, and a megabyte (MB) is equal to 1,000,000 bytes. However, some operating systems and software may use the decimal and binary systems interchangeably, which can lead to discrepancies in the reported storage capacities, as explained in the &lt;a href="https://www.iec.ch/prefixes-binary-multiples" rel="noopener noreferrer"&gt;IEC&lt;/a&gt; article.&lt;/p&gt;
&lt;h4&gt;
  
  
  Metric Prefixes
&lt;/h4&gt;

&lt;p&gt;Units representing larger groups of bits and bytes use the &lt;a href="https://en.wikipedia.org/wiki/Metric_prefix" rel="noopener noreferrer"&gt;metric prefixes&lt;/a&gt;. Here is an overview:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;General terms&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;byte&lt;/td&gt;
&lt;td&gt;1 byte&lt;/td&gt;
&lt;td&gt;One byte&lt;/td&gt;
&lt;td&gt;One ASCII character&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kilobyte (KB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;3&lt;/sup&gt;  bytes&lt;/td&gt;
&lt;td&gt;One thousand bytes&lt;/td&gt;
&lt;td&gt;2-3 paragraphs of text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Megabyte (MB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;6&lt;/sup&gt;  bytes&lt;/td&gt;
&lt;td&gt;One million bytes&lt;/td&gt;
&lt;td&gt;Picture taken by a smartphone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gigabyte (GB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;9&lt;/sup&gt;  bytes&lt;/td&gt;
&lt;td&gt;One billion bytes&lt;/td&gt;
&lt;td&gt;A movie downloaded to your device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terabyte (TB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;12&lt;/sup&gt; bytes&lt;/td&gt;
&lt;td&gt;One trillion bytes&lt;/td&gt;
&lt;td&gt;1,000 movies downloaded to your device&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Binary-Based Units
&lt;/h4&gt;

&lt;p&gt;Units based on powers of 2 have slightly different prefixes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value (in bytes)&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Approximate Decimal Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;byte&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;sup&gt;10&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Kibibyte (KiB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;3&lt;/sup&gt; = 1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;sup&gt;20&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Mibibyte (MiB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;6&lt;/sup&gt; = 1,000,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;sup&gt;30&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Gibibyte (GiB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;9&lt;/sup&gt; = 1,000,000,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;sup&gt;40&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Tebibyte (TiB)&lt;/td&gt;
&lt;td&gt;10&lt;sup&gt;12&lt;/sup&gt; = 1,000,000,000,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Prefix generation
&lt;/h4&gt;

&lt;p&gt;The prefixes for binary-based units were generated by combining the standard metric prefixes with “bi,”  resulting in “Kibi,” “Mebi,” “Gibi,” and “Tebi.” See example below:&lt;br&gt;
&lt;strong&gt;Ki&lt;/strong&gt;lo + &lt;strong&gt;Bi&lt;/strong&gt;nary = Kibi&lt;br&gt;
&lt;strong&gt;Me&lt;/strong&gt;ga + &lt;strong&gt;Bi&lt;/strong&gt;nary = Mebi&lt;br&gt;
&lt;strong&gt;Gi&lt;/strong&gt;ga + &lt;strong&gt;Bi&lt;/strong&gt;nary = Gibi&lt;br&gt;
&lt;strong&gt;Te&lt;/strong&gt;ra + &lt;strong&gt;Bi&lt;/strong&gt;nary = Tebi&lt;/p&gt;
&lt;h2&gt;
  
  
  Memory Model in Python
&lt;/h2&gt;

&lt;p&gt;We have seen the importance of space in algorithms. Ideally, we want to limit how much space our program uses and also optimize our program so that they can use the fast parts of the memory hierarchy. Before we can do that, we have to understand how the Python program stores data.&lt;/p&gt;

&lt;p&gt;How are Python objects stored in Memory?&lt;br&gt;
Remember that in Python, all data is represented as an object. These include numbers, strings, lists, functions, and classes. Each object has properties/attributes and methods.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Stack and the Heap
&lt;/h2&gt;

&lt;p&gt;When a Python program executes, all of its data is stored in the main memory.&lt;br&gt;
It creates a runtime stack and dynamic memory heap. &lt;/p&gt;
&lt;h3&gt;
  
  
  The Stack
&lt;/h3&gt;

&lt;p&gt;Functions and variables are created in the stack.&lt;br&gt;
A new stack frame is created on the invocation of a function or method. Inside the stack frame, we have local variables and parameters.&lt;br&gt;
A stack frame is destroyed as soon as the function or method returns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def my_function1():
    x = 4
    print(x)

def my_function2():
    y = 7
    return y

my_function1()
print(my_function2())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s click through our example step by step using an online &lt;a href="https://pythontutor.com/visualize.html#mode=edit" rel="noopener noreferrer"&gt;visualizer&lt;/a&gt;.&lt;br&gt;
Step 1: It creates a global frame for the functions.&lt;br&gt;
Step 2: It accesses the variable within the scope and prints it in the terminal.&lt;br&gt;
Step 3: &lt;code&gt;my_function1()&lt;/code&gt; returns None because we didn’t use a return statement, while &lt;code&gt;my_function2()&lt;/code&gt; returns 7.&lt;/p&gt;
&lt;h4&gt;
  
  
  Scope
&lt;/h4&gt;

&lt;p&gt;We can't talk of a stack frame without discussing the concept of scope.&lt;br&gt;
There are two types of scopes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local scope&lt;/strong&gt;: Variables and functions within a function are only accessible through that function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Global scope&lt;/strong&gt;: Variables and functions declared outside any function have a global scope. They are accessible from anywhere in the program, including within functions. Using global variables excessively is generally not recommended because as your program grows, you find it hard to think of a variable name as everything is already used, leading to a name clash and many other reasons. You can check out this &lt;a href="https://www.baeldung.com/cs/global-variables#:~:text=Global%20Variables%20Reduce%20Modularity%20and,how%20that%20affects%20the%20other." rel="noopener noreferrer"&gt;article&lt;/a&gt; for a detailed explanation of why global variables are generally bad.&lt;/p&gt;

&lt;p&gt;In summary, think of a local scope as functions and variables declared in a function and a global scope as functions and variables declared outside a function. When you create a function, you automatically create a scope for the variables and functions inside, and for this reason, we use a return value to end the function and return a value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = 5
print(y)

def my_function():
    x = 4
    print(x)

my_function()
print(x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s click through our example step by step.&lt;br&gt;
Step 1: It creates a global frame for &lt;code&gt;y&lt;/code&gt;.&lt;br&gt;
Step 2: It gets printed to the terminal.&lt;br&gt;
Step 3: It executes &lt;code&gt;my_function()&lt;/code&gt; and returns &lt;code&gt;None&lt;/code&gt;.&lt;br&gt;
Step 4: When it gets to &lt;code&gt;print(x)&lt;/code&gt; it returns a &lt;code&gt;NameError&lt;/code&gt;. But why? &lt;br&gt;
The answer boils down to scope. &lt;code&gt;x&lt;/code&gt; is within the scope of &lt;code&gt;my_function()&lt;/code&gt; so when Python tries to find &lt;code&gt;x&lt;/code&gt; it checks the global scope and when it can’t find it, it returns an error. &lt;/p&gt;

&lt;p&gt;Let’s look at another example. Step through the code.&lt;br&gt;
&lt;/p&gt;

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

def my_function():
    x = 4
    print(x)

my_function()
print(x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 1: It creates a global frame for &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;my_function()&lt;/code&gt;.&lt;br&gt;
Step 2: It prints out &lt;code&gt;x&lt;/code&gt; and returns &lt;code&gt;None&lt;/code&gt;.&lt;br&gt;
Step 3: It checks for &lt;code&gt;x&lt;/code&gt; in the global frame and prints it out.&lt;/p&gt;

&lt;p&gt;Let’s take a look at another example.&lt;br&gt;
&lt;/p&gt;

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

def my_function():
    print(x)

my_function()

And another.

def my_function():
    x = 5
    return x

x = my_function()
print(x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a rule of thumb, Python typically looks for a variable's name by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;looking at the current frame.&lt;/li&gt;
&lt;li&gt;If not found, looking at the global frame.&lt;/li&gt;
&lt;li&gt;If not found, raising an error.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The image above is a recursive function, we will dive deep into it in future tutorials. But I want you to take note of something. You can see a local and global scope as well as a call stack.&lt;br&gt;
Try debugging your programs on vscode and take note of these things. We move on to the next concept.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Heap
&lt;/h3&gt;

&lt;p&gt;Think of the stack as the reference memory address of the object on the heap.&lt;br&gt;
The heap stores the values along with its memory address. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: All values are stored in the heap. Objects are created on the heap.&lt;/p&gt;

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

&lt;p&gt;When we discuss heap there are two concepts we have to learn.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reference counting&lt;/li&gt;
&lt;li&gt;Garbage Collector&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A value in memory has references to the stack, or the stack references the value in memory. More than one stack can reference a value in memory. Once we reassign the variables in the stack it points to another memory address and another until the reference is 0. The garbage collector will deallocate it from memory. This is done automatically, so you won't have to worry about it. So this algorithm used for garbage collection is called reference counting.&lt;/p&gt;

&lt;p&gt;To see this in action, step through this code using the online visualizer. What did you notice?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = ['a', 'b', 'c']
y = x
print(x)
print(y)

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

&lt;/div&gt;



&lt;p&gt;Answer: Two arrows are pointing to the object on the heap.&lt;/p&gt;

&lt;p&gt;Let’s make it even more fun. We will use an &lt;code&gt;id&lt;/code&gt; to print its memory address on the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = ['a', 'b', 'c']
y = x
print(id(x))
print(id(y))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see more examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# purpose - want to switch the values i.e x = 3, y = 1

x = 1
y = 3
x = y
y = x

print(x)  # result: 3
print(y)  # result: 3

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

&lt;/div&gt;



&lt;p&gt;This doesn’t work because we have lost &lt;code&gt;x&lt;/code&gt;value in the process of reassignment. Let’s create a &lt;code&gt;temp&lt;/code&gt; variable to store the value of &lt;code&gt;x&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = 1
y = 3
temp = x
x = y
y = temp

print(x)
print(y)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s use another method and it works the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = 1
y = 3
x, y = y, x

print(x)
print(y)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create an object in Python and compare the memory address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

point1 = Point(1, 2)
point2 = Point(3, 4)
print(point1 == point2)  # result: False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns &lt;code&gt;False&lt;/code&gt; for this reason.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: When comparing objects we are comparing the address they contain in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutability
&lt;/h2&gt;

&lt;p&gt;Immutable objects cannot be modified by the program. All primitive data types are immutable.&lt;br&gt;
E.g., strings, integers, floats, booleans, and tuples.&lt;br&gt;
You may argue that you can reassign a variable containing these primitives and it does change.&lt;br&gt;
But here is the deal. In your eyes, when it gets reassigned, it changes, but in memory, it simply changes the reference. Do you remember that the stack is a reference to the value in the heap? So if the memory address were previously 1021, now it would point to 1053. If no variable references 1053 anymore, the reference count is 0, and it gets garbage collected.&lt;/p&gt;

&lt;p&gt;Mutable objects can be modified. E.g. Lists, dict, and user-defined object types.&lt;/p&gt;

&lt;p&gt;We might not be able to visualize this properly using the online visualizer, so I have used a diagram and &lt;code&gt;id&lt;/code&gt; to explain it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name = 'Praise'
print(id(name))  # result: 140700969655408

name = 'John'
print(id(name))  # result: 140700766157320

print(name)  # result: John
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Step 1: It points an arrow to 1011(lets imagine that's the memory address of &lt;code&gt;Praise&lt;/code&gt;).&lt;br&gt;
Step 2: When we reassign it points it to 1022.&lt;/p&gt;

&lt;p&gt;Step through this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;names = ['Praise', 'John', 'Paul']
print(id(names))

names[0] = 'Tinuke'
print(names)
print(id(names))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will notice that the memory address is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding how objects are made
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A space is created in memory for our object.&lt;/li&gt;
&lt;li&gt;The variable is initialized using &lt;strong&gt;init&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;reference&lt;/strong&gt; to the object created is returned.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tracing Code using diagrams
&lt;/h2&gt;

&lt;p&gt;The best way to understand how memory works is to write some codes and see the step-by-step execution of memory. I have shown you some examples so far. Look at the codes you have previously written and step through them. Python tutor visualizer has some limitations, so you would have to use the debugging tools in your code editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources &amp;amp; References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pythontutor.com/render.html#mode=edit" rel="noopener noreferrer"&gt;Python tutor visualizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kibo.school/" rel="noopener noreferrer"&gt;Kibo&lt;/a&gt; DSA lecture material &lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/zDNaUi2cjv4?si=CzMwJevLDIVTAsJZ" rel="noopener noreferrer"&gt;Binary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/Xpk67YzOn5w?si=NsKlHWDGLrhPOTEi" rel="noopener noreferrer"&gt;Binary and transistors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/arxWaw-E8QQ?si=2z-6YUMEfW9LVC5O" rel="noopener noreferrer"&gt;Memory allocation and management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.iec.ch/prefixes-binary-multiples" rel="noopener noreferrer"&gt;IEC article&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/U-FkUheayrs?si=2qlUw-FzIZBHzR--" rel="noopener noreferrer"&gt;Kibibytes, minibytes, gigabytes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ascii-code.com/" rel="noopener noreferrer"&gt;ASCII chart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this lesson, you have learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage and Memory&lt;/li&gt;
&lt;li&gt;Short-term and long-term memory&lt;/li&gt;
&lt;li&gt;Memory hierarchy&lt;/li&gt;
&lt;li&gt;Measuring Space&lt;/li&gt;
&lt;li&gt;Stacks, Heaps, Scopes, References, Garbage collector, and Mutability&lt;/li&gt;
&lt;li&gt;Tracing the code using an online visualizer tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Until next time, for more insights:&lt;br&gt;
☕ If you enjoy my content, you can buy me a cup of coffee &lt;a href="https://www.buymeacoffee.com/ifeoluwapru" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
📰 To read more from me, subscribe to my newsletter.&lt;br&gt;
🧸 Check my social media profiles: &lt;a href="https://x.com/PraiseID3?t=WqgSov3o-htz89CukDu3oA&amp;amp;s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://github.com/praise002" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>dsa</category>
      <category>memorymanagement</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Practice Projects</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Sat, 10 Feb 2024 15:22:14 +0000</pubDate>
      <link>https://dev.to/praise002/practice-projects-524l</link>
      <guid>https://dev.to/praise002/practice-projects-524l</guid>
      <description>&lt;p&gt;Welcome to the second project in this series. In this project, you will modify the code by breaking it into simple functions and refactoring it. This will teach you how to organize your code. By the end of this project, you will be prepared to tackle the remaining exercises.&lt;/p&gt;

&lt;p&gt;To access the project file and README, click &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/tree/master/chapter-9/practice-projects" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Code
&lt;/h2&gt;

&lt;p&gt;Open the project README. You are working on Project 1 which is “ Selective Copy”. Make sure you understand what you are to do before moving on to read the code.&lt;br&gt;
This project will teach you how to read people code and improve on the code. In the real-world you will probably be working on code written by previous engineers, you are likely not going to write new codes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os, shutil, sys

# walk through a dir tree
# create a list of file extensions to copy
# copy it to a new folder


def select_copy(src, dest):
    src = os.path.abspath(src)
    dest = os.path.abspath(dest)

    extensions = ['.pdf', '.jpg', '.png']

    # Check if the provided path is a directory
    if not os.path.isdir(src):
        print(f'The path "{src}" you have provided is not a directory')
        return  # used to exit the function

    # walk the dir tree
    for folder_name, subfolders, filenames in os.walk(src):
        for filename in filenames:
            for extension in extensions:
                if filename.endswith(extension):
                    print(filename)

                    # check if the dest exists
                    if not os.path.exists(dest):
                        os.mkdir(dest)

                    # copy it to a new folder
                    shutil.copy(os.path.join(folder_name, filename), dest)



if __name__ == '__main__':
    src = r"C:\Users\Praise Idowu\Desktop\test2"
    dest = r"C:\Users\Praise Idowu\Desktop\test4"
    select_copy(src, dest)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the program. Let us move on to the refactoring phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring
&lt;/h2&gt;

&lt;p&gt;If a variable like &lt;code&gt;subfolders&lt;/code&gt; is not utilized, it is a Python convention to replace it with an underscore (‘_’). Replace &lt;code&gt;subfolders&lt;/code&gt; with an underscore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for folder_name, subfolders, filenames in os.walk(src):
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create three functions, each with a parameter.&lt;br&gt;
Multiline strings explain the purpose of each function. Implement and test your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os, shutil, sys
def select_files(src, extensions):
    """
    Select files with specified extensions from the source directory.


    Parameters:
    - src (str): Source directory path.
    - extensions (list): List of file extensions to select.


    Returns:
    - list: List of selected file paths.
    """
    pass


def copy_files(selected_files, dest):
    """
    Copy selected files to the destination directory.


    Parameters:
    - selected_files (list): List of file paths to copy.
    - dest (str): Destination directory path.
    """
    pass       

def select_copy(src, dest, extensions):
    """
    Select files with specified extensions from the source directory
    and copy them to the destination directory.


    Parameters:
    - src (str): Source directory path.
    - dest (str): Destination directory path.
    - extensions (list): List of file extensions to select.
    """   
    pass           


if __name__ == '__main__':
    pass

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Exercise
&lt;/h2&gt;

&lt;p&gt;Complete the remaining two exercises in the practice project and share your code as well.&lt;/p&gt;

&lt;p&gt;We have come to the end of this series.&lt;/p&gt;

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

&lt;p&gt;You already have the skills needed to organize and manipulate files. Moving forward, you will work on complex automation projects. Until next time, happy coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why learn Data structures and Algorithm</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Sat, 03 Feb 2024 16:27:55 +0000</pubDate>
      <link>https://dev.to/praise002/why-learn-data-structures-and-algorithm-47c0</link>
      <guid>https://dev.to/praise002/why-learn-data-structures-and-algorithm-47c0</guid>
      <description>&lt;p&gt;What crosses your mind when the term "data structures and algorithms" (DSA) is mentioned? Let me take a guess – FAANG(Facebook, Apple, Amazon, Netflix, Google) interviews, perhaps? Spot on. Chances are, that's exactly why you are here. DSA may appear intimidating, leaving you questioning its significance. However, in today’s world, where efficiency is key and competition is fierce, mastery of DSA has become vital. Maybe you have been immersed in coding for years without needing it, and then suddenly, an interview arises, demanding you to quickly acquire DSA skills. Alternatively, it could be a pivotal course in your Computer Science curriculum, or there might be another reason altogether. &lt;/p&gt;

&lt;p&gt;In this article, we will cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is a data structure?&lt;/li&gt;
&lt;li&gt;What is an algorithm?&lt;/li&gt;
&lt;li&gt;Big-O time and space efficiency.&lt;/li&gt;
&lt;li&gt;Why should you learn DSA?&lt;/li&gt;
&lt;li&gt;How to learn DSA.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Data Structure?
&lt;/h2&gt;

&lt;p&gt;A data structure is a way to store and organize data to allow us to efficiently access and modify the data. Operations performed on this data include adding information, searching for it, or removing it.&lt;/p&gt;

&lt;p&gt;Let's consider a real-world example. Picture yourself at a library needing a book on Organic Chemistry. You locate the Chemistry shelf, but it contains all sorts of books unrelated to Chemistry.&lt;br&gt;
Because the shelf is disorganized, you spend a longer time searching for the book, which might eventually lead you to check other shelves as well because, who knows, it could be on the linguistics shelf.&lt;/p&gt;

&lt;p&gt;Now, envision an organized scenario. You reach the science shelf, find a section for Chemistry, and within that, distinct sections for Organic Chemistry. Suddenly, your search becomes effortless.&lt;/p&gt;

&lt;p&gt;In computer science, how we organize data is crucial for easy retrieval. Choosing the appropriate data structure can significantly improve code efficiency.&lt;/p&gt;
&lt;h3&gt;
  
  
  Examples of Data Structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arrays/Lists&lt;/strong&gt;: Ordered, mutable collections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dictionaries/Objects/Maps&lt;/strong&gt;: Unordered, mutable key-value pairs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sets&lt;/strong&gt;: Unordered, mutable collections of unique elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tuples&lt;/strong&gt;: Ordered, immutable collections.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What is an Algorithm?
&lt;/h3&gt;

&lt;p&gt;An algorithm is a set of instructions to perform a computation. Simply put, it involves operations on different data structures along with a set of instructions for executing them.&lt;/p&gt;

&lt;p&gt;Let's consider a real-world example.&lt;/p&gt;

&lt;p&gt;Imagine you want to teach your five-year-old brother to draw a circle.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Put a small pencil in the compass.&lt;/li&gt;
&lt;li&gt;Align the pencil in the compass to ensure its tip matches the width of the divider.&lt;/li&gt;
&lt;li&gt;Measure the radius on a ruler.&lt;/li&gt;
&lt;li&gt;Place the divider on the paper and move it in a circular motion until it forms a circle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There you have it – you have just implemented an algorithm.&lt;/p&gt;

&lt;p&gt;Now, let's transition to a programming example:&lt;br&gt;
Imagine you are to write a program to calculate the sum of two numbers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define two variables to represent the two numbers.&lt;/li&gt;
&lt;li&gt;Use an arithmetic operation to add the two numbers.&lt;/li&gt;
&lt;li&gt;Return the sum.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def find_sum(num1, num2):
    sum = num1 + num2
    return sum

if __name__ == '__main__':
  sum = find_sum(5, 7)
  print("The sum is:", sum)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JavaScript Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function findSum(num1, num2) {
    let sum = num1 + num2;
    return sum;
};

// Example usage:
let sum = findSum(5, 7);
console.log("The sum is:", sum);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's discuss the space and time efficiency of an algorithm.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Space and time efficiency?
&lt;/h3&gt;

&lt;p&gt;Space and time efficiency is concerned with how the algorithm utilizes two essential resources: space and time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Space&lt;/strong&gt;: This refers to memory and storage considerations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt;: This refers to the speed at which the algorithm operates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next tutorial, we will discuss Memory where we will dive into this deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Big-O Notation?
&lt;/h2&gt;

&lt;p&gt;Big-O notation can be used to describe an algorithm's space and time efficiency. It provides a set of rules to measure both space and time complexities.&lt;/p&gt;

&lt;p&gt;Let's consider two functions.&lt;br&gt;
A: Sort(): Modifies the original array and returns an ordered array.&lt;br&gt;
B: Sorted(): Creates a new sorted array without modifying the original iterable.&lt;/p&gt;

&lt;p&gt;Given solutions A and B, which one is more efficient in terms of space?&lt;/p&gt;

&lt;p&gt;Answer: A is more efficient in terms of space because it uses minimal memory.&lt;br&gt;
B needs more space to hold the new sorted array.&lt;/p&gt;

&lt;p&gt;Now that we have clarified the key terms, let's proceed to answer the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why learn DSA?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Improve Problem-Solving Skills&lt;/strong&gt;: This is a fundamental skill for programmers. DSA teaches you to think, rapidly improving your problem-solving ability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Help in Solving Real-world Problems&lt;/strong&gt;: DSA assists in selecting the right data structures and algorithms to tackle real-world issues. Consider a social network or map; a graph algorithm can be instrumental in solving such problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write Optimized Code&lt;/strong&gt;: DSA improves efficiency in terms of both space and time. Optimized code runs faster, utilizes less memory, and is overall more efficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prepare for Technical Interviews&lt;/strong&gt;: Leading companies like FAANG often ask questions related to DSA in technical interviews. Familiarity with DSA concepts becomes crucial in attaining success in these interviews.&lt;/p&gt;

&lt;p&gt;I know this has been a lot to grasp so far. Now, you might be wondering how to start and what resources you need. These questions will be answered shortly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to learn DSA?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Be comfortable in a programming language e.g Python, JavaScript, C, Java, etc&lt;/li&gt;
&lt;li&gt;Start with searching and sorting algorithms because it is much easier to understand before diving into complex algorithms.&lt;/li&gt;
&lt;li&gt;Understand, don't memorize; visualize and write pseudocode.&lt;/li&gt;
&lt;li&gt;Scrabble algorithm on paper.&lt;/li&gt;
&lt;li&gt;Watch various videos for implementation insights.&lt;/li&gt;
&lt;li&gt;Apply algorithms in real-world projects, reflecting on past coding challenges.&lt;/li&gt;
&lt;li&gt;Consider the big-O space-time complexity to determine the efficiency of your code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtube.com/playlist?list=PLzgPDYo_3xukPJdH6hVQ6Iic7KiJuoA-l&amp;amp;si=RkokOtJVsztPs5zR" rel="noopener noreferrer"&gt;Python-DSA&lt;/a&gt; &amp;amp; &lt;a href="https://youtube.com/playlist?list=PLzgPDYo_3xunyLTJlmoH8IAUvet4-Ka0y&amp;amp;si=bse_WbsqXnnqscxS" rel="noopener noreferrer"&gt;Sorting algorithms&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/playlist?list=PLC3y8-rFHvwjPxNAKvZpdnsr41E0fCMMP&amp;amp;si=tpr1XiQN4qXIQGP_" rel="noopener noreferrer"&gt;Javascript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codewithmosh.com/p/data-structures-algorithms" rel="noopener noreferrer"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codewithmosh.com/p/interview-preparation-bundle" rel="noopener noreferrer"&gt;Interview Preparation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/" rel="noopener noreferrer"&gt;Leetcode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://log2base2.com/dsa" rel="noopener noreferrer"&gt;Log2base2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Data Structures and Algorithms are key concepts in computer science. It can help you write efficient code and pass interviews.&lt;/p&gt;

&lt;p&gt;Check out the next article where I delve into DSA in-depth.&lt;/p&gt;

&lt;p&gt;Until then, for more insights:&lt;br&gt;
☕ If you enjoy my content, you can buy me a cup of coffee &lt;a href="https://www.buymeacoffee.com/ifeoluwapru" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
📰 To read more from me, subscribe to my newsletter.&lt;br&gt;
🧸 Check my social media profiles: &lt;a href="https://x.com/PraiseID3?t=WqgSov3o-htz89CukDu3oA&amp;amp;s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://github.com/praise002" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>datastructures</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Renaming Files with American-Style Dates to European-Style Dates</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Sat, 27 Jan 2024 08:50:59 +0000</pubDate>
      <link>https://dev.to/praise002/renaming-files-with-american-style-dates-to-european-style-dates-28n8</link>
      <guid>https://dev.to/praise002/renaming-files-with-american-style-dates-to-european-style-dates-28n8</guid>
      <description>&lt;p&gt;Welcome to the first project in this series. In this project you will rename files with American-Style dates to European-Style dates. You will combine your knowledge of regular expressions and file organization. To follow along with this project, access the project file &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/tree/master/chapter-9/rename-dates-american-style" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before starting let us see if you are prepared for this project. Read the prerequisites below before moving on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure you have a good understanding of the following resources before tackling this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File Organization &lt;/li&gt;
&lt;li&gt;Series 1 and 2&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Understand the project
&lt;/h3&gt;

&lt;p&gt;Assuming they are all organized in this format: MM-DD-YYYY.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9hxeleg7wfnr43w3zyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9hxeleg7wfnr43w3zyp.png" alt="An image showing MM-DD-YYYY format" width="315" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we want to achieve is this format: DD-MM-YYYY.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujvcyki9wk9gr7rtkega.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujvcyki9wk9gr7rtkega.png" alt="An image showing DD-MM-YYYY format" width="342" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Observe the first image, what did you notice?&lt;br&gt;
Once you are done, check out my answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observation 1&lt;/strong&gt;: Only the day and month need to be swapped.&lt;br&gt;
&lt;strong&gt;Observation 2&lt;/strong&gt;: Some of the filenames have a prefix before the dates.&lt;br&gt;
&lt;strong&gt;Observation 3&lt;/strong&gt;: The prefix is separated from the dates with an underscore.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Write code
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Import the Required Modules&lt;br&gt;
The &lt;code&gt;os&lt;/code&gt;,  &lt;code&gt;sys&lt;/code&gt;,  and &lt;code&gt;re&lt;/code&gt; modules have been used in several other projects, so you should already be familiar with them.&lt;br&gt;
The &lt;code&gt;shutil&lt;/code&gt; module is used to perform operations such as copying, moving, and renaming files. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create a function with one parameter: &lt;code&gt;root_dir&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Create a regex pattern.&lt;br&gt;
Comments have been used to explain it. But overall, the pattern matches American-Style dates with years in the 19's and 20's.&lt;br&gt;
&lt;code&gt;re.compile&lt;/code&gt; is used to compile a regular expression pattern into a regex object, allowing you to reuse the pattern for matching operations.&lt;/p&gt;

&lt;p&gt;Question: Can you identify how many groups are in this pattern? Remember that a group is separated by () parenthesis. Drop your answers in the comments section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Test the pattern.&lt;br&gt;
To test the pattern, visit this &lt;a href="https://www.regexpal.com/" rel="noopener noreferrer"&gt;website&lt;/a&gt;, hover over each pattern and it interprets it as a character, metacharacter and so on. On the right side of the website, you will find a cheat sheet for reference. Paste some filenames in both correct and incorrect patterns to see if they match.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Loop through all files in the &lt;code&gt;root_dir&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Search each file for pattern match.&lt;br&gt;
Do you remember what &lt;code&gt;.search&lt;/code&gt; does? It finds the first occurrence of a pattern in a string and returns a match object, while &lt;code&gt;.findall&lt;/code&gt; returns all occurrences of the pattern as a list of strings.&lt;br&gt;
Print out the match object to see what it returns, then comment it out and proceed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Check if a match is found and if true, it returns a date component.&lt;br&gt;
&lt;code&gt;match.groups()&lt;/code&gt; returns a tuple. You can unpack the tuple by assigning its elements to individual variables, such as &lt;code&gt;month&lt;/code&gt;, &lt;code&gt;day&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;, and &lt;code&gt;_&lt;/code&gt;. The underscore &lt;code&gt;_&lt;/code&gt; is often used as a placeholder for values you want to ignore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8&lt;/strong&gt;: Rename the filename to the European-Style date: DD-MM-YYYY.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Give it a variable name; &lt;code&gt;new_filename&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use f-string to give it the desired name: This line uses an f-string to construct the &lt;code&gt;new_filename&lt;/code&gt;. Here's a breakdown of how it works:&lt;/li&gt;
&lt;li&gt;filename[:match.start()]: This part takes the portion of the original filename from the beginning up to the start of the match. It effectively includes everything before the matched text.&lt;/li&gt;
&lt;li&gt;{day}-{month}-{year}: This part adds the date components (day, month, and year) extracted from the match. They are separated by hyphens to create a date format.&lt;/li&gt;
&lt;li&gt;filename[match.end():]: This part takes the portion of the original filename from the end of the match to the end of the string. It effectively includes everything after the matched text.&lt;/li&gt;
&lt;li&gt;Print the filename to check that it works correctly: You can use &lt;code&gt;print(new_filename)&lt;/code&gt; to verify that the new filename is generated as expected. Once you confirm that it's working correctly, you can comment out the print statement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In summary, this code creates a new filename by replacing the matched portion of the original filename with the extracted date components in a specific format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 9&lt;/strong&gt;: Get the old and new file_path and store them in a variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10&lt;/strong&gt;: Use &lt;code&gt;shutil.move()&lt;/code&gt; to rename it.&lt;br&gt;
Before running the code, it's a good practice to comment out the &lt;code&gt;shutil.move()&lt;/code&gt; line. After verifying that the print statement works correctly and provides the expected file paths, you can uncomment it to actually rename the files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11&lt;/strong&gt;: The last part is checking if a root directory is specified by calculating the length. Remember that &lt;code&gt;sys.argv&lt;/code&gt; returns a list, so you can check the length of this list to see if a root directory is specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os, shutil, re, sys

# let us assume all files are in the American Style dates and we want files in the 19's and 20's

def rename_files(root_dir):
    # Create a regex pattern for American-style dates (MM-DD-YYYY)   
    date_pattern = re.compile(
        r'''
        (0[1-9]|1[0-2])-  # matches 01-09 or 10-12 for month with a '-' character
        (0[1-9]|[12]\d|3[01])- # matches 01-31 for days
        ((19|20)\d{2})  # matches the 19's and 20's for year
        ''', re.VERBOSE
    )

    # Loop through all files in the current directory
    for filename in os.listdir(root_dir):
        # Check if the filename contains a date in American style
        match = date_pattern.search(filename)

        if match:  # not None
            # Extract the date components
            month, day, year, _ = match.groups()  # returns a tuple
            # Rename the file with European-style date (DD-MM-YYYY)
            new_filename = f'{filename[:match.start()]}{day}-{month}-{year}{filename[match.end():]}'
            print(new_filename)

            old_filepath = os.path.join(root_dir, filename)
            new_filepath = os.path.join(root_dir, new_filename)

            # Rename the file using shutil.move()
            shutil.move(old_filepath, new_filepath)
            print(f'Renamed: {filename} -&amp;gt; {new_filename}')
            print()

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('Usage: python main.py [root_dir]')
        exit(1)

    try:
        root_dir = sys.argv[1]  
        rename_files(root_dir)
    except FileNotFoundError as e:
        print(e)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the result on the terminal. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6crmhwy380np5gi5h0bq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6crmhwy380np5gi5h0bq.png" alt="Terminal showing the result of the code" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise 1
&lt;/h3&gt;

&lt;p&gt;Use the os module to rename files. Give it a try!&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise 2
&lt;/h3&gt;

&lt;p&gt;Complete the exercises listed under "Ideas for Similar Program." You can find the questions &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/tree/master/chapter-9/rename-dates-american-style" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Once you have completed them, share the link to your solution in the comments section.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>automation</category>
    </item>
    <item>
      <title>Creating Python Virtual Environment on Windows 11</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Sat, 20 Jan 2024 16:01:32 +0000</pubDate>
      <link>https://dev.to/praise002/creating-python-virtual-environment-on-windows-11-1fkm</link>
      <guid>https://dev.to/praise002/creating-python-virtual-environment-on-windows-11-1fkm</guid>
      <description>&lt;p&gt;When you work on a Python project, the conventional approach involves globally installing a Python interpreter and creating a file named &lt;code&gt;filename.py&lt;/code&gt;. Typically, as you advance into more complex Python tasks, you may use &lt;code&gt;pip&lt;/code&gt; to install packages globally.&lt;/p&gt;

&lt;p&gt;While this method might not pose a problem initially, it can become a concern as you move into specialized areas such as Data Science, Data Analytics, or Backend development.&lt;/p&gt;

&lt;p&gt;Imagine a scenario: you have Project A where you have installed version 1.0 of  a package. Then you switch to Project B and install the same package but version 2.0. Upon returning to Project A, you encounter issues—this is what we call breaking changes.&lt;/p&gt;

&lt;p&gt;In the following sections, I will walk you through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating, activating, and deactivating a virtual environment&lt;/li&gt;
&lt;li&gt;Reproducing a virtual environment&lt;/li&gt;
&lt;li&gt;Installing packages within the virtual environment&lt;/li&gt;
&lt;li&gt;Specifying the Python interpreter when creating the virtual environment &lt;/li&gt;
&lt;li&gt;Configuring and using a virtual environment in VSCode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s address the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a virtual environment?
&lt;/h2&gt;

&lt;p&gt;A virtual environment serves as a secluded space to store project dependencies. It is an isolated environment where project dependencies are stored.&lt;/p&gt;

&lt;p&gt;Within each virtual environment, there is a specific Python version it runs on and folders of third-party libraries you have installed. Virtual environments make it easy to keep track of project dependencies, particularly useful when working on projects with dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzqhnox4qq1soddjxxv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzqhnox4qq1soddjxxv5.png" alt="Diagramatic representation of a virtual environement" width="298" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you think of a virtual environment, picture the two key components shown in the figure above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsgzjul0d92bhjrrwsz3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsgzjul0d92bhjrrwsz3.png" alt="An illustration of multiple virtual environments" width="777" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The figure above illustrates what you have on your system when you create multiple virtual environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a dependency?
&lt;/h2&gt;

&lt;p&gt;A dependency is a code written by other people that we can install and use on our project so we don’t have to rewrite it. However, this practice introduces potential compatibility issues, conflicts, or breaking changes, especially since every package tends to release new versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic Versioning
&lt;/h3&gt;

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

&lt;p&gt;The figure above illustrates the major, minor, and patch versions. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is a pip?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/pip/" rel="noopener noreferrer"&gt;Pip&lt;/a&gt; is a package management tool in Python that we can use to install these dependencies. Visit &lt;a href="https://pypi.org/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;(Python Package Index) to install and publish Python packages. Click &lt;a href="https://docs.python.org/3/tutorial/modules.html#packages" rel="noopener noreferrer"&gt;here&lt;/a&gt; to learn more about modules and packages.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run the above on the CLI to see a list of &lt;code&gt;pip&lt;/code&gt; commands. Feeling adventurous? Play around the commands and come back to continue reading.&lt;/p&gt;

&lt;p&gt;Mostly when you are working with virtual environments, you use &lt;code&gt;pip&lt;/code&gt; alongside it to install dependencies. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why installing packages globally using pip is a bad idea
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It becomes challenging to keep track of project dependencies across different projects when packages are installed globally.&lt;/li&gt;
&lt;li&gt;When working on a new project and installing the same package, pip automatically uninstalls the previous version. This can lead to compatibility issues with other projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a look at the tools to create virtual environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools for creating virtual environments
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;venv&lt;/li&gt;
&lt;li&gt;virtualenv&lt;/li&gt;
&lt;li&gt;pipenv&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Venv
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.python.org/3/library/venv.html" rel="noopener noreferrer"&gt;Venv&lt;/a&gt; is a lightweight built-in module in Python 3.3 and later versions for creating virtual environments requiring no installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;mkdir env&lt;br&gt;
py -m venv env/my_env&lt;/code&gt;&lt;br&gt;
&lt;code&gt;my_env&lt;/code&gt; is the name of the virtual environment. Replace &lt;code&gt;my_env&lt;/code&gt; with the name of the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Activating a virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;.\my_env\Scripts\activate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now run this:&lt;br&gt;
&lt;code&gt;pip list&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command lets you see the packages you installed in the virtual environment. For now, only pip is available in the virtual environment. &lt;br&gt;
Installing packages into the virtual environment&lt;br&gt;
&lt;code&gt;pip install python-decouple&lt;br&gt;
pip install pillow&lt;br&gt;
pip install django&lt;br&gt;
pip install django-autoslug&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Install the above packages. Now run the &lt;code&gt;pip list&lt;/code&gt;. You can see a list of dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deactivating a virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;deactivate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To deactivate the environment, run the above command and run the &lt;code&gt;pip list&lt;/code&gt; again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reproducing the virtual environment
&lt;/h3&gt;

&lt;p&gt;From the documentation, it says the virtual environment should be simple to delete and recreate from scratch.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt;&lt;br&gt;
Delete the virtual environment, create a virtual environment, and activate it. Then run the command below:&lt;br&gt;
&lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is particularly useful when collaborating on a project. You want to recreate the virtual environment on your machine.&lt;br&gt;
NOTE: Always .gitignore the folder where the virtual environment is created.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specify the Python Interpreter while creating the virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;py –list&lt;/code&gt;&lt;br&gt;
Run the above command to see a list of Python versions installed on your system. Automatically Python uses the latest version installed. If you want to use another version while creating the virtual environment, run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;py -X.Y -m venv myenv: e.g py -3.9 -m venv myenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;NOTE: If the Python version is not installed or in the path you will get the error below. To install Python, click &lt;a href="https://www.python.org/downloads/windows/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6fp4pphgy9vnrqa7hbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6fp4pphgy9vnrqa7hbn.png" alt="An image showing an error message on the terminal" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtualenv
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://virtualenv.pypa.io/en/latest/" rel="noopener noreferrer"&gt;Virtualenv&lt;/a&gt; is a third-party &lt;a href="https://www.geeksforgeeks.org/libraries-in-python/amp/" rel="noopener noreferrer"&gt;library&lt;/a&gt; requiring installation that is used to create virtual environments in Python. It has been available in earlier versions of Python such as Python 2. It is still being used; however, since Python 3.3, a subset of it has been integrated into the standard library under the &lt;code&gt;venv&lt;/code&gt; module. &lt;code&gt;Venv&lt;/code&gt; is not a replacement for &lt;code&gt;virtualenv&lt;/code&gt;. It has small differences with the &lt;code&gt;virtualenv&lt;/code&gt; library. To learn more about it, visit the documentation. &lt;/p&gt;

&lt;p&gt;To get started using it you have to install the virtualenv library.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install pipx&lt;br&gt;
pipx install virtualenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can choose to use &lt;code&gt;pip&lt;/code&gt; to install the library except for a small difference; the documentation recommended using &lt;code&gt;pipx&lt;/code&gt; for the installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;virtualenv my_env&lt;/code&gt;&lt;br&gt;
This creates a folder in your current directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Activate the environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;.\my_env\Scripts\activate&lt;/code&gt;&lt;br&gt;
This activates the virtual environment.&lt;br&gt;
Specify the Python Interpreter while creating the virtual environment&lt;br&gt;
&lt;code&gt;virtualenv -p python-interpreter-path&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You need the right path that ends with &lt;code&gt;python.exe&lt;/code&gt;. You can easily get this path by checking the path in environment variables.&lt;br&gt;
"C:\path\to\your\python.exe" &lt;br&gt;
"C:\Users&amp;lt;YourUsername&amp;gt;\AppData\Local\Programs\Python\Python3x\python.exe" &lt;br&gt;
NB: Replace &lt;code&gt;x&lt;/code&gt; with the version. &lt;br&gt;
It should look like this on your system:&lt;br&gt;
&lt;code&gt;virtualenv -p "C:\Users\&amp;lt;YourUsername&amp;gt;\AppData\Local\Programs\Python\Python312\python.exe" my_env&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtualenvwrapper
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://virtualenvwrapper.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Virtualenvwrapper&lt;/a&gt; creates and activates the virtual environment. It keeps all your environment in one place. It is an extension to the &lt;code&gt;virtualenv&lt;/code&gt; tool. With virtualenvwrapper, you only need to type &lt;code&gt;workon&lt;/code&gt; to switch between virtual environments. You can run the same command to see a list of virtual environments.&lt;br&gt;
For windows we have a special package we use called &lt;a href="https://pypi.org/project/virtualenvwrapper-win/#:~:text=The%20idea%20behind%20virtualenvwrapper%20is,7%2F8%2F10" rel="noopener noreferrer"&gt;virtualenvwrapper-win&lt;/a&gt;. It only works on command prompt, so be sure to switch to a command prompt.&lt;br&gt;
&lt;code&gt;pip install virtualenvwrapper-win&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mkvirtualenv &amp;lt;name&amp;gt;&lt;/code&gt;&lt;br&gt;
Replace  with &lt;code&gt;venv&lt;/code&gt; or any other name.&lt;br&gt;
&lt;code&gt;lsvirtualenv&lt;/code&gt;&lt;br&gt;
It displays the list of virtual environments that have been created.&lt;br&gt;
&lt;code&gt;workon &amp;lt;name&amp;gt;&lt;/code&gt;&lt;br&gt;
It activates the virtual environment. If the name is not specified, it lists the available environments.&lt;br&gt;
&lt;code&gt;deactivate&lt;/code&gt;&lt;br&gt;
It deactivates the virtual environment.&lt;br&gt;
To learn more commands you can check out the docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipenv
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pipenv.pypa.io/en/latest/" rel="noopener noreferrer"&gt;Pipenv&lt;/a&gt; is a virtualenv management tool and a package management tool. It combines venv or virtualenv and pip in a single command. It also works alongside pyenv and asdf to manage multiple python environments. It automatically creates a virtual environment and can be used for installation of packages as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Pipenv Tool
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pip install pipenv&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Activate the virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pipenv shell&lt;/code&gt;&lt;br&gt;
NOTE: If you install a package with the &lt;code&gt;pipenv&lt;/code&gt; command without activating the virtual environment, it will create a virtual environment for the project and ask you to run &lt;code&gt;pipenv shell&lt;/code&gt; to activate it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install packages
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pipenv install django&lt;br&gt;
pipenv install python-decouple&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Specify a version
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pipenv --python 3.9&lt;/code&gt;&lt;br&gt;
The version of Python specified must be installed on your system or it will request you to install &lt;code&gt;pyenv&lt;/code&gt; or &lt;code&gt;asdf&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exit the virtual environment
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Exit&lt;/code&gt; or &lt;code&gt;exit&lt;/code&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Reproducing the virtual environment
&lt;/h3&gt;

&lt;p&gt;To recreate it. All you have to do is run this command, and it installs all the dependencies from Pipfile. To learn more about its features read the docs.&lt;br&gt;
&lt;code&gt;pipenv install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;NOTE: If &lt;code&gt;pyenv&lt;/code&gt; is available it will automatically install the required Python version.&lt;/p&gt;

&lt;p&gt;To learn more about the commands click &lt;a href="https://pipenv.pypa.io/en/latest/cli.html" rel="noopener noreferrer"&gt;here&lt;/a&gt; or run &lt;code&gt;pipenv&lt;/code&gt; on the CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring and using a virtual environment in VSCode
&lt;/h2&gt;

&lt;p&gt;To switch the virtual environment on Vs Code, look at the bottom right of the code editor. You can click on it to switch between interpreters. Another way is using a keyboard shortcut &lt;code&gt;ctrl+shift+p&lt;/code&gt;, and the command palette pops up. Search for Python interpreters to switch between interpreters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4f1asabkdi1607om3kzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4f1asabkdi1607om3kzy.png" alt="An image showing the Python Interpreter on the terminal" width="800" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Others:&lt;br&gt;
&lt;a href="https://python-poetry.org/" rel="noopener noreferrer"&gt;Poetry&lt;/a&gt;: This is a Python packaging and dependency management tool. You will likely find it useful if your focus is on packaging and dependency management such as publishing a package to PyPI.&lt;br&gt;
&lt;a href="https://conda.io/projects/conda/en/latest/user-guide/getting-started.html" rel="noopener noreferrer"&gt;Conda&lt;/a&gt;: It is a package management and environment management system. You will most likely find it useful if you are into data science or scientific computing. It is not limited to these two careers but it is widely used in data science and scientific computing.&lt;/p&gt;

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

&lt;p&gt;In this tutorial we learned about virtual environments and their importance in managing multiple project dependencies. We used built-in modules and third-party libraries to create virtual environments. The choice of which virtual environment to choose from might be confusing at first but except for small differences, it doesn’t matter. The choice depends on your preferences and project standards. If you are a beginner you can start with &lt;code&gt;venv&lt;/code&gt; since it is the easiest to set up. When you get comfortable with it you can explore other virtualenv and stick to it.&lt;/p&gt;

&lt;p&gt;Until then, for more insights:&lt;br&gt;
☕ If you enjoy my content, you can buy me a cup of coffee &lt;a href="https://www.buymeacoffee.com/ifeoluwapru" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
🧸 Check my social media profiles: &lt;a href="https://x.com/PraiseID3?t=WqgSov3o-htz89CukDu3oA&amp;amp;s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://github.com/praise002" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, and &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>backenddevelopment</category>
      <category>virtualenv</category>
    </item>
    <item>
      <title>Project: Regex Search</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Sat, 13 Jan 2024 09:53:14 +0000</pubDate>
      <link>https://dev.to/praise002/project-regex-search-4en6</link>
      <guid>https://dev.to/praise002/project-regex-search-4en6</guid>
      <description>&lt;p&gt;Welcome to the third project in this series. In this project, you will automate the searching of user-supplied text patterns within text files.&lt;br&gt;
To follow along with this project, you can access the project files and READMEs &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/tree/master/chapter-8%2Fregex_search" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before embarking on this project, make sure you have completed Part 2 of the series.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Structure:
&lt;/h2&gt;

&lt;p&gt;This project follows a logical structure aimed at helping you grasp the concepts and build the skills progressively. Here is how we will approach it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start Simple&lt;/strong&gt;: We will begin with a straightforward approach to achieve basic functionality. Our primary goal is to make the code work as intended, even if it is not perfect initially. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refine and Enhance&lt;/strong&gt;: Once your code is functional, we will start improving it. This phase will involve optimizing the code for better performance and usability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Challenge Yourself&lt;/strong&gt;: As usual, there will be an exercise at the end of the project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the project file in a separate tab and follow along with these steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Understand the Project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# provide the absolute path to the directory
# search the directory of any .txt files
# Open each file
# Search for lines that match the user-supplied regex
# print the matching result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Import the Required Modules.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import os, re&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Create a Function.&lt;br&gt;
Create a function with two parameters: &lt;code&gt;dir_path&lt;/code&gt; and &lt;code&gt;user_supplied_regex&lt;/code&gt;. This function will be used to perform the desired regex search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def regex_search(dir_path, user_supplied_regex):
    # Your code goes here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Get the Absolute Path of the Directory.&lt;br&gt;
Use &lt;code&gt;os.path.abspath(dir_path)&lt;/code&gt; to get the absolute path of the directory. Ensure you specify &lt;code&gt;dir_path&lt;/code&gt; as a raw string to prevent the character from escaping.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if __name__ == '__main__':
    dir_path = r'C:\Users\Praise Idowu\Documents\blog-projects\Automating-the-boring-stuff-with-Python-blog-project\chapter-8\regex_search\folder1'
    user_supplied_regex = None
    regex_search(dir_path, user_supplied_regex)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Loop Through the Files.&lt;br&gt;
Use a &lt;code&gt;for&lt;/code&gt; loop to iterate through the filenames in the specified directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Check if it is a File.&lt;br&gt;
Use the &lt;code&gt;os.path.isfile(filepath)&lt;/code&gt; to check if the current item is a file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Check the File Extension.&lt;br&gt;
Use &lt;code&gt;os.path.splitext(filepath)&lt;/code&gt; to split the file extension from the filename. It returns a tuple and you can access the extension using indexing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8&lt;/strong&gt;: Check if it is a &lt;code&gt;.txt&lt;/code&gt; File and Print the Filename.&lt;br&gt;
Use a conditional statement to check if the file has a &lt;code&gt;.txt&lt;/code&gt; extension. If it does, print the filename. Once your code is working correctly, comment out the print statement and move on to the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 9&lt;/strong&gt;: Open the File and Read its Content.&lt;br&gt;
Open the file in read mode and store its content in a variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10&lt;/strong&gt;: Compile the User-Supplied Regex and Find Matches.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile the user-supplied regex pattern using re.compile(user_supplied_regex, re.VERBOSE).&lt;/li&gt;
&lt;li&gt;Use re.findall() to find all occurrences of the regex pattern in the file's content.&lt;/li&gt;
&lt;li&gt;If matches are found, print them as the results.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os, re

def regex_search(dir_path, user_supplied_regex):
    # provide abs path
    dir = os.path.abspath(dir_path)
    # print(dir)
    for filename in os.listdir(dir):
        # print(filename)
        if os.path.isfile(os.path.join(dir, filename)):
            # print(filename)
            split_file = os.path.plaintext(os.path.join(dir, filename))
            # print(split_file)
            # searches the directory for any .txt files
            if split_file[1] == '.txt':
                print(filename)

                # It opens the folder
                with open(os.path.join(dir, filename), 'r', encoding='utf-8') as f:
                    content = f.read()
                # print(content)

                # It searches for a line that matches the user-supplied regex
                user_regex = re.compile(user_supplied_regex, re.VERBOSE)
                for groups in user_regex.findall(content):
                    # it prints the result
                    print(groups)



if __name__ == '__main__':
    dir_path = r'C:\Users\Praise Idowu\Documents\blog-projects\Automating-the-boring-stuff-with-Python-blog-project\chapter-8\regex_search\folder1'
    # user_supplied_regex = r'web | scraping'
    user_supplied_regex = r'''(
        (https?://)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?
        )'''
    regex_search(dir_path, user_supplied_regex)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The previous code works well, but it can be improved. Here are the updates that have been made:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Removed repetition of &lt;code&gt;os.path.join&lt;/code&gt; and created a &lt;code&gt;file_path&lt;/code&gt; variable to replace it.&lt;/li&gt;
&lt;li&gt;Used &lt;code&gt;filename.endswith&lt;/code&gt; to check for the '.txt' extension. It returns a boolean.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os, re

def regex_search(dir_path, user_supplied_regex):
    # Provide an absolute path
    dir = os.path.abspath(dir_path)

    # Create a regex pattern from the user-supplied regex
    user_regex = re.compile(user_supplied_regex, re.VERBOSE)

    for filename in os.listdir(dir):
        file_path = os.path.join(dir, filename)

        # Check if the file is a .txt file
        if os.path.isfile(file_path) and filename.endswith('.txt'):
            print(filename)

            # Open and read the file
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()

            # Search for matches in the content
            matches = user_regex.findall(content)

            # Print the matched line
            for match in matches:
                print(match)

if __name__ == '__main__':
    dir_path = r'C:\Users\Praise Idowu\Documents\blog-projects\Automating-the-boring-stuff-with-Python-blog-project\chapter-8\regex_search\folder1'
    # user_supplied_regex = r'web | scraping'
    user_supplied_regex = r'''(
        (https?://)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?
        )'''
    regex_search(dir_path, user_supplied_regex)

# TODO: use input() instead
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Exercise 1
&lt;/h3&gt;

&lt;p&gt;Instead of hard-coding &lt;code&gt;dir_path&lt;/code&gt; and &lt;code&gt;user_supplied_regex&lt;/code&gt;, use the &lt;code&gt;input()&lt;/code&gt; function to prompt the user to enter these values interactively.&lt;/p&gt;
&lt;h3&gt;
  
  
  Exercise 2
&lt;/h3&gt;

&lt;p&gt;Depending on the regex the user supplies, it can print a string, lists, or tuples. &lt;/p&gt;

&lt;p&gt;To make the code more flexible and handle different output scenarios, Tope has already implemented some code but needs assistance in completing it. You can improve the functionality by allowing the user to choose the output format (default, returns a string, list of tuples, or tuples) and providing an option for indexing or slicing if the user chooses to do that. &lt;/p&gt;

&lt;p&gt;Additionally, Tope has specified &lt;code&gt;match[0]&lt;/code&gt; which isn't what we want, you can enable the user to specify the index they want to access in the results (e.g., 0, 1, etc.). After completing the code, don't forget to share your repository link in the comments section for feedback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Print the matched line
for match in matches:
  # Extract and print all groups in the match
  # print(type(match))
  if isinstance(match, tuple):
     print(match[0])
  elif isinstance(match, list):
     pass
  else:
     print(match)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this project, you have gained valuable skills in text processing and pattern matching. We have come to the end of this series, moving forward you will write code to organize files.&lt;/p&gt;

&lt;p&gt;If you have any questions, want to connect, or just fancy a chat, feel free to reach out to me on &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://twitter.com/PraiseID3?s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>automation</category>
    </item>
    <item>
      <title>Comparing CodiumAI PR-Agent to GitHub Copilot's solution for pull request</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Mon, 18 Dec 2023 20:09:35 +0000</pubDate>
      <link>https://dev.to/praise002/comparing-codiumai-pr-agent-to-github-copilots-solution-for-pull-request-1lfe</link>
      <guid>https://dev.to/praise002/comparing-codiumai-pr-agent-to-github-copilots-solution-for-pull-request-1lfe</guid>
      <description>&lt;p&gt;In the software development field, &lt;a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests" rel="noopener noreferrer"&gt;pull requests&lt;/a&gt;(PRs) play a crucial role in fostering collaboration. However, it’s not uncommon for us to overlook essential tasks before submitting a pull request. This oversight can result in rejection - whether due to unclear and lengthy descriptions or the omission of test cases for code updates. Code reviews, though vital, often consume a considerable amount of time. For developers, this can become a &lt;a href="https://dev.to/pragyanatvade/6-differences-you-must-know-between-a-good-pull-request-pr-vs-a-bad-pull-request-pr-5fho"&gt;daunting experience&lt;/a&gt;, especially when they are maintaining larger projects with multiple contributors. But what if there was a way to speed up the pull request process? In this article, we will compare two tools that have the potential to speed up pull request processes. We will explore the features and capabilities of both tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  CodiumAI PR Agent
&lt;/h2&gt;

&lt;p&gt;CodiumAI PR-Agent is an AI tool that automates the PR review process. It can track your &lt;a href="https://en.wikipedia.org/wiki/Changeset#:~:text=A%20changeset%20describes%20the%20exact,set%2C%20by%20version%20control%20systems." rel="noopener noreferrer"&gt;changeset&lt;/a&gt; and provides comprehensive reviews before you create a pull request. &lt;/p&gt;

&lt;p&gt;This tool can be integrated into your code editor and git provider(GitHub, GitLab, etc.) environment. &lt;/p&gt;

&lt;p&gt;As a developer, this tool is valuable when creating a PR. It helps communicate the changes made to other developers and ensures that updates and test cases are not brittle.&lt;/p&gt;

&lt;p&gt;As a maintainer, you can use this tool to review changes and provide feedback before merging them into the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;To start using CodiumAI PR-Agent. You can install it on your &lt;a href="https://en.m.wikipedia.org/wiki/Integrated_development_environment" rel="noopener noreferrer"&gt;IDE&lt;/a&gt; or initiate it on GitHub by using the @CodiumAI-Agent command. If you are the one reviewing the PR you might want to use it on your git provider and if you are the one making a PR you might want to use it on your IDE. &lt;br&gt;
To install it on your IDE or git provider, click &lt;a href="https://www.codium.ai/products/git-plugin/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
Now that you are done installing it, let us discuss its features.&lt;/p&gt;

&lt;h3&gt;
  
  
  PR-Agent Features
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcw39nn4mh7ao81m80zzr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcw39nn4mh7ao81m80zzr.png" alt="Image of CodiumAI commands" width="800" height="372"&gt;&lt;/a&gt;&lt;br&gt;
The PR-Agent offers a range of advanced features, designed to elevate your pull request process. PR-Agent supports a variety of commands. You can check out an example demo &lt;a href="https://github.com/praise002/test-pr/pull/2" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  /describe
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo73f8mb7rd5jf48b27sh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo73f8mb7rd5jf48b27sh.png" alt="Image of the describe command in action" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this command, PR-Agent retrieves the title, type(label), description, and main files walkthrough of the changeset ensuring that the essential details are captured accurately.&lt;/p&gt;

&lt;h4&gt;
  
  
  /ask
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6jwehqca8sm14avncwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6jwehqca8sm14avncwx.png" alt="Image of the ask command in action" width="698" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR-Agent allows you to ask questions related to the changeset in your code. &lt;/p&gt;

&lt;h4&gt;
  
  
  /review
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxhfe341xjcyk0yu957s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxhfe341xjcyk0yu957s.png" alt="Image of review command in action" width="696" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;PR-Agent conducts a comprehensive review of the changeset, including code quality, potential bugs, and improvement suggestions. It ensures that your changeset is polished before submission. &lt;/p&gt;

&lt;h4&gt;
  
  
  /improve
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hve2reednfrlyzerzkd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hve2reednfrlyzerzkd.png" alt="Image of the improve command in action" width="718" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimjdvy01wc1r5cr05g6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimjdvy01wc1r5cr05g6n.png" alt="Image of the improve command in action" width="675" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bcyf7x7hbalujyfudah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bcyf7x7hbalujyfudah.png" alt="Image of the improve command in action" width="617" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR-Agent provides code improvements focused on the changeset, contributing to overall code quality.&lt;/p&gt;

&lt;h4&gt;
  
  
  /add_doc
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcijwfc75or4p0qixnq47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcijwfc75or4p0qixnq47.png" alt="Image of add_docs command in action" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qjv4g2kc0uvhxiq4w24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qjv4g2kc0uvhxiq4w24.png" alt="Image of add_docs command in action" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When invoked, this command automatically creates a docstring. This enhances the readability of your codebase and is valuable for anyone working with or contributing to the project.&lt;/p&gt;

&lt;p&gt;In addition to these features, PR-Agent offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IDE integration: Seamlessly incorporate PR-Agent into your integrated development environment(&lt;a href="https://www.codium.ai/install/" rel="noopener noreferrer"&gt;IDE&lt;/a&gt;) such as (Vs Code, IntelliJ, WebStorm, CLion, JetBrains, Pycharm, etc).&lt;/li&gt;
&lt;li&gt;Support multiple git providers such as (GitHub, Gitlab, Bitbucket, CodeCommit).&lt;/li&gt;
&lt;li&gt;Support for all major programming languages.&lt;/li&gt;
&lt;li&gt;Multiple ways to use the tool(CLI, GitHub Action, GitHub App, Docker, etc).&lt;/li&gt;
&lt;li&gt;Multiple &lt;a href="https://github.com/Codium-ai/pr-agent/pull/172" rel="noopener noreferrer"&gt;models&lt;/a&gt; (GPT-4, GPT-3.5, Anthropic, Cohere, Llama2).
To learn more, click &lt;a href="https://github.com/Codium-ai/pr-agent#installation" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot is an AI pair programmer that simplifies the process of code writing, making it faster and more efficient. It offers a range of other capabilities. For this article, our focus will be on its pull request (PR) solution. As of writing this article, GitHub PR is still on the waitlist. Here are some of its features.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Copilot PR Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Suggestions for your pull request description.&lt;/li&gt;
&lt;li&gt;Identification of PR changes lacking tests, with automated suggestions for test creation.&lt;/li&gt;
&lt;li&gt;Real-time generation of text suggestions as you type.&lt;/li&gt;
&lt;li&gt;Issue resolution, code suggestion generation, and initiation of new pull requests.&lt;/li&gt;
&lt;li&gt;PR completion and repair functionalities&lt;/li&gt;
&lt;li&gt;AI-powered review and responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub Copilot PR features from &lt;a href="https://githubnext.com/projects/copilot-for-pull-requests" rel="noopener noreferrer"&gt;GithubNext&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Limitations of AI-PR Agents: CodiumAI PR-Agent and GitHub Copilot PR
&lt;/h2&gt;

&lt;p&gt;In exploring the potential capabilities of these tools, it’s important to know that these tools, just like every AI come with their drawbacks. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For instance, the automated suggestions may not always align with project requirements leading to inaccuracies in the generated code.&lt;/li&gt;
&lt;li&gt;The feedback might be inaccurate emphasizing the need for additional prompts to ensure precise feedback.&lt;/li&gt;
&lt;li&gt;It is still under development signifying ongoing refinement and improvement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison between CodiumAI PR-Agent and Github Copilot PR
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Repository Accessibility
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR-Agent is open-source, allowing public access, while GitHub Copilot PR resides within a private repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR is free to use for individual developers but there are paid plans that offer more features. In contrast, GitHub Copilot PR requires a paid subscription.&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform Support
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR supports all Git platforms while GitHub Copilot PR is exclusive to GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Availability
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR is available for use right now. On the other hand, GitHub Copilot PR is presently on a waitlist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Command Support
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR supports a variety of commands as we have seen earlier and it will support more commands in the future, whereas GitHub Copilot PR primarily supports one command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Large Language Model
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR uses multiple models while GitHub Copilot PR is powered by the OpenAI GPT-4 model.&lt;/p&gt;

&lt;h3&gt;
  
  
  IDE Support
&lt;/h3&gt;

&lt;p&gt;CodiumAI PR can be integrated into your IDE such as (&lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Vs Code&lt;/a&gt;, &lt;a href="https://www.jetbrains.com/" rel="noopener noreferrer"&gt;JetBrains IDE's&lt;/a&gt;, etc). In contrast, GitHub Copilot PR can be integrated into Vs Code, Visual Studio, Neovim, and JetBrains IDEs.&lt;/p&gt;

&lt;h2&gt;
  
  
  CodiumAI PR-Agent Git Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;: Aims to improve collaboration by speeding up the PR process.&lt;br&gt;
&lt;strong&gt;Changelog Updates&lt;/strong&gt;: Assists in updating changelogs with relevant information.&lt;br&gt;
&lt;strong&gt;Concise title and description&lt;/strong&gt;: Enables contributors to write concise and meaningful descriptions.&lt;br&gt;
&lt;strong&gt;Commit message assistance&lt;/strong&gt;: Generates meaningful commit messages.&lt;br&gt;
&lt;strong&gt;Code quality evaluation and improvement&lt;/strong&gt;: Analyzes code for quality, potential bugs, and improvement suggestions.&lt;br&gt;
&lt;strong&gt;Q&amp;amp;A&lt;/strong&gt;: Addresses contributor's questions related to the changeset.&lt;/p&gt;

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

&lt;p&gt;In summary, both CodiumAI PR-Agent and GitHub Copilot PR present valuable PR solutions to simplify and improve the pull request process. The choice between these tools depends on specific project requirements and preferences.&lt;/p&gt;

&lt;p&gt;What sets CodiumAI PR-Agent apart is not just its features but also its commitment to openness and collaboration. Being an open-source solution, it enables developers globally to contribute, inspect the source code, and collectively improve the tool. This transparency not only builds trust but also fosters a community-driven approach, ensuring continuous innovation.&lt;/p&gt;

</description>
      <category>codiumai</category>
      <category>ai</category>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Multi Clipboard</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Fri, 15 Dec 2023 21:22:41 +0000</pubDate>
      <link>https://dev.to/praise002/multi-clipboard-35mj</link>
      <guid>https://dev.to/praise002/multi-clipboard-35mj</guid>
      <description>&lt;h2&gt;
  
  
  Project: Multi Clipboard
&lt;/h2&gt;

&lt;p&gt;Welcome to the second project in this series. You will be building a functional Multiclipboard. Before you begin, let's talk about what a clipboard does.&lt;/p&gt;

&lt;p&gt;A clipboard helps you copy and paste, but once you make another copy, it erases the last copy. This is where a Multiclipboard comes into play. It helps you store text with a certain keyword and access as many texts as possible making it possible for you to retrieve a particular text.&lt;/p&gt;

&lt;p&gt;To learn more about the project, check out this &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/tree/master/chapter-8/multiclipboard" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Part 1 of the series&lt;/li&gt;
&lt;li&gt;Optionally, &lt;a href="https://www.python.org/downloads/release/python-390/" rel="noopener noreferrer"&gt;Python 3.9&lt;/a&gt; or an earlier version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that you have gone through the README, let's proceed. In this project, you will find exercises at the end of the project, which can involve fixing a bug or organizing the functions. Be sure to check the project files for reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a file called &lt;code&gt;mcb.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: In this step, we will take a different approach. We want to define the functions and their respective command line arguments.&lt;/p&gt;

&lt;p&gt;You can see that we have defined three functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;save_keyword should take a keyword and its content as arguments.&lt;/li&gt;
&lt;li&gt;load_text should take a keyword as an argument and load its content.&lt;/li&gt;
&lt;li&gt;list_keywords() does not require any arguments; it simply displays all the keywords.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach will help you structure your code effectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# save_keyword(keyword, content), load_text(keyword), list_keywords()
# Usage: 
# py mcb.py save &amp;lt;keyword&amp;gt; - Saves clipboard to keyword.
# py mcb.py &amp;lt;keyword&amp;gt; - Loads keyword to clipboard.
# py mcb.py list - Loads all keywords to the clipboard.
# py mcb.py clear - clears all keywords
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: The next step is to decide how to save the keyword and its content. You have three options to choose from, although the README suggests using shelve. Let's briefly explore your options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dictionary&lt;/strong&gt;: Using a dictionary allows you to store data during program execution, but it won't persist data after closing the program.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save to a File&lt;/strong&gt;: This approach involves saving the dictionary to a file, allowing you to read and write data to and from the file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shelve&lt;/strong&gt;: &lt;a href="https://docs.python.org/3/library/shelve.html" rel="noopener noreferrer"&gt;Shelve&lt;/a&gt; provides a dictionary-like behavior, but it is different in that it acts as a persistent, on-disk storage system. Data saved using shelve remains accessible even after you close the program, making it a suitable choice for this project. You can think of it as a way to store data for the long term.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Import the Necessary Modules&lt;br&gt;
sys: allows you to interact with the command line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import pyperclip, shelve, sys&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Create Functions&lt;br&gt;
You have now created five functions, two additions to the ones defined earlier.&lt;br&gt;
Let's look at these additions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;delete_keyword takes a keyword as input and deletes it along with its associated contents.&lt;/li&gt;
&lt;li&gt;The run function is where the program's logic is written.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def save_keyword_with_content(keyword, content):
    pass

def list_keywords():
    pass

def load_content(keyword):
    pass

def delete_keyword(keyword):
    pass

def run():
    pass  

if __name__ == '__main__':
    run()

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

&lt;/div&gt;


&lt;p&gt;It's time to dive in and start putting these functions to work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: save_keyword_with_content, list_keywords, load_content, delete_keyword&lt;/p&gt;

&lt;p&gt;In this step, you have defined the save_keyword_with_content function. It takes a keyword and content as arguments and uses the shelve module to create or open a shelf with the specified prefix. It then stores the content under the given keyword on the shelf.&lt;br&gt;
&lt;/p&gt;

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

def save_keyword_with_content(keyword, content):
     # Open and close a shelf file
    with shelve.open(prefix) as mcb_shelf:
        mcb_shelf[keyword] = content

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

&lt;/div&gt;



&lt;p&gt;In the list_keywords function, you want to return a list of all the keywords (keys) stored in the shelve, but you need to return this list as a string. Here's the breakdown:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;mcb_shelf.keys(): This part retrieves all the keys (keywords) from the mcb_shelf object. These keys are initially in a format that is not a string.&lt;/li&gt;
&lt;li&gt;list(mcb_shelf.keys()): You convert the keys into a list format using list(). Now, you have a list of the keywords.&lt;/li&gt;
&lt;li&gt;str(list(mcb_shelf.keys())): Lastly, you use str() to convert this list of bytes objects into a string format. This is necessary because your function is expected to return a string. By converting the list to a string, you ensure it can be returned in a human-readable format, as byte objects are not easily human-readable.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def list_keywords():
    # Open and close a shelf file
    with shelve.open(prefix) as mcb_shelf:
        # return keys list
        return str(list(mcb_shelf.keys()))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have created the load_content function. It opens the shelf using the prefix and retrieves the content associated with the provided keyword from the shelf.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def load_content(keyword):
    with shelve.open(prefix) as mcb_shelf:
        return mcb_shelf[keyword]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this step, you have defined the delete_keyword function. It opens the shelf with the prefix and checks if the keyword exists on the shelf. If it does, it deletes the keyword and its associated content. If the keyword is not found, it prints a message and exits the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def delete_keyword(keyword):
    with shelve.open(prefix) as mcb_shelf: 
        if keyword in mcb_shelf.keys():
            del mcb_shelf[keyword]
        else:
            print(f'{keyword} not found. It must have been deleted.')
            sys.exit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You must have noticed something in these functions. What is it you noticed?&lt;/p&gt;

&lt;p&gt;These functions all repeat the same code for opening the shelf. This repetition is a violation of the DRY (Don't Repeat Yourself) principle, which suggests that code should be reused or abstracted to avoid redundancy. We will address this issue later in your project to make the code more efficient and maintainable. Let's move on for now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: You define the run function, which handles different command-line arguments to interact with your Multi Clipboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def run():
    if len(sys.argv) == 3:
        # save clipboard content
        if sys.argv[1].lower() == 'save':
            keyword = sys.argv[2]
            content = pyperclip.paste()
            save_keyword_with_content(keyword, content)
        # delete keyword
        elif sys.argv[1].lower() == 'delete':  
            keyword = sys.argv[2]
            delete_keyword(keyword)
            print(f'{keyword} deleted with contents.')
            print(list_keywords())

    # list keywords and load content
    elif len(sys.argv) == 2:
        keywords = list_keywords()
        if sys.argv[1].lower() == 'list':
            pyperclip.copy(keywords)
            print(keywords)
        elif sys.argv[1] in keywords:
            keyword = sys.argv[1]
            content = load_content(keyword)
            pyperclip.copy(content)
            print(content)

    else:
        print(f'''Usage: python your_script.py save &amp;lt;keyword&amp;gt;
                python your_script.py &amp;lt;keyword&amp;gt;
                python your_script.py list''')      

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

&lt;/div&gt;



&lt;p&gt;To test it, you should run your script in a terminal or command prompt, passing the appropriate arguments.&lt;/p&gt;

&lt;p&gt;Here is how you can test it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal or command prompt.&lt;/li&gt;
&lt;li&gt;Test the different functionalities with the following commands:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;To save content to a keyword:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;python your_script.py save my keyword&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To delete a keyword:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python your_script.py delete mykeyword&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To list all keywords:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python your_script.py list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To load content from a specific keyword:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python your_script.py mykeyword&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace &lt;code&gt;mykeyword&lt;/code&gt; with an actual keyword, and the script should perform the corresponding action as defined in the run function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise 1
&lt;/h3&gt;

&lt;p&gt;Create a function called clear_keywords without any parameters. This function will clear all keywords stored in the mcb_shelf. Additionally, handle errors properly so that if the shelf is empty, it responds with a clear message instead of generating error messages. You can run this function by executing &lt;code&gt;py mcb.py clear&lt;/code&gt; in the command line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise 2
&lt;/h3&gt;

&lt;p&gt;You will realize this code works well but as you write more code you want to write clean and efficient code, minimizing repetition.&lt;br&gt;
In this exercise, the goal is to address the redundancy of opening the shelve function in multiple parts of your code.&lt;/p&gt;

&lt;p&gt;Once you are done, the solution can be found in fix_repitition.py in the project directory.&lt;/p&gt;
&lt;h3&gt;
  
  
  Exercise 3
&lt;/h3&gt;

&lt;p&gt;In this exercise, we focus on improving the provided code by addressing issues related to repetition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if len(sys.argv) == 3:
        # save clipboard content
        if sys.argv[1].lower() == 'save':
            keyword = sys.argv[2]
            content = pyperclip.paste()
            save_keyword_with_content(keyword, content)
        # delete keyword
        elif sys.argv[1].lower() == 'delete':  
            keyword = sys.argv[2]
            delete_keyword(keyword)
            print(f'{keyword} deleted with contents.')
            print(list_keywords())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To improve the code, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define the keyword variable in the outer loop, allowing both the save and delete sections to access it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exercise 4
&lt;/h3&gt;

&lt;p&gt;After making the code structure more robust, we have identified another issue with the functionality when saving text. &lt;/p&gt;

&lt;p&gt;Run this on the command line: py mcb.py save text1. Copy several different texts and run them again. What did you notice?&lt;/p&gt;

&lt;p&gt;Currently, it overrides the previous content, which may not be desirable. In this exercise, we aim to address this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: To prevent content from being overridden when saving text, you can use an if-else statement to check if the key already exists. If it exists, return a warning message; otherwise, save the new content.&lt;/p&gt;

&lt;p&gt;Now, the program works as expected. What if you want to ask the user for confirmation? I know right now you are thinking, well I am the only user of my program. You want to think of a real-world scenario where you have several users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: If the key already exists and you want to provide the user with an option to replace it, you can add more code to ask the user if they would like to replace the existing content. This step involves integrating user input and conditional logic to determine whether to replace the content.&lt;/p&gt;

&lt;p&gt;These improvements ensure that the Multi Clipboard functions more naturally, avoiding accidental content loss and allowing user interaction when necessary.&lt;/p&gt;

&lt;p&gt;Once you are done, for a detailed solution, you can refer to the "fix_repitition2.py" file provided in the project directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise 5
&lt;/h3&gt;

&lt;p&gt;There is one more issue we need to address to make our program more robust.&lt;/p&gt;

&lt;p&gt;When users want to delete an item, it's common practice to ask for their confirmation to avoid accidental deletions. However, there is a problem with the current code, and we need to identify and correct it.&lt;/p&gt;

&lt;p&gt;To resolve this issue, carefully review the code to find any errors that might be causing the problem. Once identified, make the necessary adjustments to ensure that the deletion confirmation process functions correctly.&lt;/p&gt;

&lt;p&gt;For a detailed solution and to compare your answer, please refer to the "mcb2.py" file provided in your project directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def run():
    if len(sys.argv) == 3:
        # save clipboard content
        if sys.argv[1].lower() == 'save':
            keyword = sys.argv[2]
            content = pyperclip.paste()
            save_keyword_with_content(keyword, content)
        # delete keyword
        elif sys.argv[1].lower() == 'delete':  #TODO: CTA: Are you sure you want to
            keyword = sys.argv[2]
            while True:
                user_input = input(are you sure you want to delete {keyword}: ').lower()
                if user_input == 'yes' or 'y':  # fix this issue not working
                    delete_keyword(keyword)
                    print(f'{keyword} deleted with contents.')
                    print(list_keywords())
                    sys.exit()
                elif user_input == 'no' or 'n':  #fix:not working
                    print('Deletion abolished')
                    sys.exit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exercise 6
&lt;/h3&gt;

&lt;p&gt;In this exercise, you will create a dictionary and practice writing it to a file to persist the data. This exercise provides an opportunity to hone your skills in writing data into files.&lt;/p&gt;

&lt;p&gt;To complete this exercise, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instead of using &lt;code&gt;shelve&lt;/code&gt;, create an empty dictionary for storage. Store the keywords as the key and the content as the value.&lt;/li&gt;
&lt;li&gt;Each time you create a new keyword, you want to store it and its content in a file to persist the data. Are you using 'w' or 'a'? What encoding will you use? Answer all these questions in your code editor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you are done implementing these steps, test your code and submit your repository link in the comments section.&lt;/p&gt;

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

&lt;p&gt;We have reached the end of this project. It is important to remember that programming is an ever-evolving journey. If you believe some areas could be further improved, don't hesitate to revisit the code. In the world of programming, inspiration can strike at any moment, even days or months later.&lt;/p&gt;

&lt;p&gt;Throughout this project, you utilized various Python modules. You used the pyperclip module for text copying and pasting, employed the shelve module for data persistence, and leveraged the sys module for efficient command-line interactions. You have not only achieved functional automation but also had the chance to explore problem-solving.&lt;/p&gt;

&lt;p&gt;As you continue on your programming journey, keep in mind that each project is a stepping stone, contributing to your growth as a developer. Embrace the process, keep coding, stay curious, and enjoy problem-solving.&lt;/p&gt;

&lt;p&gt;If you have any questions, want to connect, or just fancy a chat, feel free to reach out to me on &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://twitter.com/PraiseID3?s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
    </item>
    <item>
      <title>Generating Random Quiz Files</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Thu, 07 Dec 2023 12:51:47 +0000</pubDate>
      <link>https://dev.to/praise002/generating-random-quiz-files-20d2</link>
      <guid>https://dev.to/praise002/generating-random-quiz-files-20d2</guid>
      <description>&lt;p&gt;Welcome to the first project in this tutorial series. In this project, you will learn how to read and write to files while creating random quiz files. You will broaden your knowledge of the random module by using it to shuffle questions and answers. By the end of this project, you will have automated the creation of random quiz files.&lt;/p&gt;

&lt;p&gt;What you will gain from this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You will learn how to use the os module for file operations.&lt;/li&gt;
&lt;li&gt;You will work with the random module to enhance your Python skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To get the most out of this project, you should already be familiar with "&lt;a href="https://drive.google.com/file/d/1xvF0KdMVNhrCb9St4OWs0L8d4nbsM1o-/view?usp=drivesdk" rel="noopener noreferrer"&gt;Automate the Boring Stuff&lt;/a&gt;: 'Python Programming Basics' and 'Reading and Writing to Files'".&lt;/li&gt;
&lt;li&gt;Willingness to learn and tackle more complex exercises.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to follow this project:
&lt;/h3&gt;

&lt;p&gt;For clarity and to avoid confusion, especially with nested loops:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the project file in a separate tab and always refer back to it.&lt;/li&gt;
&lt;li&gt;The “...” was used to indicate that the code has been truncated, just as you would do in your code editor when dealing with long lines of code. &lt;/li&gt;
&lt;li&gt;Avoid copying and pasting from here; instead, use the project file.&lt;/li&gt;
&lt;li&gt;It is often better to write small sections of code and test it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let me walk you through the steps to generate random quiz files. To access the project file, click &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/tree/master/chapter-8/generate-random-quiz-files" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Write Comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files  
    # Generate 35 quiz files.
    # write out the header for the quiz        
    # Shuffle the order of the states         
    # Loop through all 50 states, making a question for each         
    # Create a list of answer options            
    # Write the question and answer options in the quiz file            
    # Write the correct answer to the answer file
    pass

if __name__ == '__main__':
    generate_random_quiz_files()

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create a file and name it &lt;code&gt;dict.py&lt;/code&gt;.&lt;br&gt;
This file contains the dictionary that stores the states and capitals. To access the dict file, click &lt;a href="https://github.com/praise002/Automating-the-boring-stuff-with-Python-blog-project/blob/master/chapter-8/generate-random-quiz-files/dict.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Below is a sample of what it looks like in the repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;capitals = {'Alabama': 'Montgomery', 'Alaska': 'Juneau', 'Arizona': 'Phoenix', 'Arkansas': 'Little Rock', 'California': 'Sacramento', 'Colorado': 'Denver',...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Import the Required Modules.&lt;br&gt;
You will import the random module, the &lt;code&gt;os&lt;/code&gt; module, and the dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random, os
from dict import capitals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Create a directory and subdirectories to store quiz and answer files.&lt;br&gt;
To ensure the program functions smoothly, start by checking if the path exists. If it doesn't, proceed to create the 'quizzes' directory. Note that we are using relative paths. If you prefer to use absolute paths, you can call the &lt;code&gt;os.path.abspath()&lt;/code&gt; function.&lt;br&gt;
After creating the directory, to create a directory tree, you will use the &lt;code&gt;os.makedirs&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer files
    if not os.path.exists('quizzes'):
        os.mkdir('quizzes/')
    if not os.path.exists('quizzes/questions):
        os.makedirs('quizzes/questions)
    if not os.path.exists('quizzes/answers'):
        os.makedirs('quizzes/answers')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the program, and only proceed to the next step if it works correctly. You should achieve a directory structure as shown below.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Generate 35 quiz files.&lt;br&gt;
Remember: The range function starts from 0 if no starting point is indicated and loops up to the endpoint, excluding the endpoint. For example, &lt;code&gt;range(35)&lt;/code&gt; starts from 0 and ends at 34, resulting in 35 files.&lt;br&gt;
Next, you will generate the question_filename. Use the &lt;code&gt;os.path.join()&lt;/code&gt; function and f-strings to create the filename.&lt;br&gt;
Lastly, test the program to ensure it functions correctly. The quickest way to do this is by using the &lt;code&gt;print()&lt;/code&gt; statement. If everything works well, you can proceed to the next step; otherwise, troubleshoot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files
    #...

    # Generate 35 quiz files.
    for quizNum in range(35):
        # Create the quiz and answer key files.
        question_filename = os.path.join('quizzes', 'questions', f'quiz_{quizNum + 1}.txt')
        answer_filename = os.path.join('quizzes', 'answers', f'quiz_{quizNum + 1}_answer.txt')
        print(question_filename)
        print(answer_filename)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Write the header for the quiz.&lt;br&gt;
First, comment out the print statement for clarity.&lt;br&gt;
Next, open the file in write mode. You use write mode to overwrite any previous generation and ensure a fresh start. The &lt;code&gt;os.path.exists()&lt;/code&gt; check you implemented earlier helps handle pre-existing folders. You also add an encoding to prevent encoding error issues, then proceed to write to the file. Ensure that you run the program to confirm it works as expected.&lt;br&gt;
Here's the updated code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files
    #...
    # Generate 35 quiz files.
    #...

        with open(question_filename, 'w', encoding='utf-8') as question_file, \
            open(answer_filename, 'w', encoding='utf-8') as answer_file:
                # write out the header for the quiz
                question_file.write('Name:\n\nDate:\n\nPeriod:\n\n')
                question_file.write(f'{" " * 20}State Capitals Quiz - Student {quizNum + 1}\n\n')
                answer_file.write(f'US State Capitals Answers - Student {quizNum + 1}\n\n')


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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;:  Shuffle the order of the states&lt;br&gt;
First, retrieve the keys, which represent the states. Store them in a variable called states, and convert this into a list because we will need a list in the next step.&lt;br&gt;
Next, shuffle the list. It is important to note that the shuffle method modifies the original list instead of creating a new one. Test it to ensure it works as expected. Try storing the shuffled list in a variable and observe the results. This will clarify the behavior of the shuffle operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files
    #...
    # Generate 35 quiz files.
    #...

        with open(question_filename, 'w', encoding='utf-8') as question_file, \
            open(answer_filename, 'w', encoding='utf-8') as answer_file:
                # write out the header for the quiz
                #...

                # Shuffle the order of the states
                states = list(capitals.keys())
                # print(states)
                random.shuffle(states)  # it does not return a new list instead it changes d original list
                print(states)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 8&lt;/strong&gt;: Loop through all 50 states, making a question for each.&lt;br&gt;
Run your code to see the results. Comment out the print statement before moving on to the next step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files
    #...
    # Generate 35 quiz files.
    #...

        with open(question_filename, 'w', encoding='utf-8') as question_file, \
            open(answer_filename, 'w', encoding='utf-8') as answer_file:
                # write out the header for the quiz
                #...

                # Shuffle the order of the states
                #...


                # Loop through all 50 states, making a question for each
                for question_num in range(50):  # it generates 1750 questions
                    state = states[question_num]  # get questions 1-50 from the list
                    correct_answer = capitals[state]  # get the capital of the state from the capitals dictionary
                    print(state)
                    print(correct_answer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 9&lt;/strong&gt;: Create a list of answer options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files
    #...
    # Generate 35 quiz files.
    #...

        with open(question_filename, 'w', encoding='utf-8') as question_file, \
            open(answer_filename, 'w', encoding='utf-8') as answer_file:
                # write out the header for the quiz
                #...

                # Shuffle the order of the states
                #...


                # Loop through all 50 states, making a question for each
                for question_num in range(50):  # it generates 1750 questions
                    #...

                    # Create a list of answer options
                    answer_options = list(capitals.values())
                    del answer_options[answer_options.index(correct_answer)]  # delete the correct answer from d anaswer options
                    wrong_answers = random.sample(answer_options, 3)
                    answer_options = wrong_answers + [correct_answer]  # conactenate list with list
                    print(answer_options)
                    random.shuffle(answer_options)
                    print(answer_options)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 10&lt;/strong&gt;: Write the question and answer options.&lt;br&gt;
In this step, you will write the questions and answer options to the quiz file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11&lt;/strong&gt;: Write the correct answer to the answer key file.&lt;br&gt;
This is the last step and you can refer back to the code for clarity. Here is the completed code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random, os
from dict import capitals


def generate_random_quiz_files():
    # Create a directory to store quiz and answer key files
    if not os.path.exists('quizzes'):
        os.mkdir('quizzes/')
    if not os.path.exists('quizzes/questions'):
        os.makedirs('quizzes/questions')
    if not os.path.exists('quizzes/answers'):
        os.makedirs('quizzes/answers')

    # Generate 35 quiz files.
    for quizNum in range(35):
        # Create the quiz and answer key files.
        question_filename = os.path.join('quizzes', 'questions', f'quiz_{quizNum + 1}.txt')
        answer_filename = os.path.join('quizzes', 'answers', f'quiz_{quizNum + 1}_answer.txt')
        # print(question_file)
        # print(answer_file)

        with open(question_filename, 'w', encoding='utf-8') as question_file, \
            open(answer_filename, 'w', encoding='utf-8') as answer_file:
                # write out the header for the quiz
                question_file.write('Name:\n\nDate:\n\nPeriod:\n\n')
                question_file.write(f'{" " * 20}State Capitals Quiz - Student {quizNum + 1}\n\n')
                answer_file.write(f'US State Capitals Answers - Student {quizNum + 1}\n\n')

                # Shuffle the order of the states
                states = list(capitals.keys())
                # print(states)
                random.shuffle(states)  # it does not return a new list instead it changes d original list
                # print(states)


                # Loop through all 50 states, making a question for each
                for question_num in range(50):  # it generates 1750 questions
                    state = states[question_num]  # get questions 1-50 from the list
                    correct_answer = capitals[state]  # get the capital of the state from the capitals dictionary
                    # print(state)
                    # print(correct_answer)

                    # Create a list of answer options
                    answer_options = list(capitals.values())
                    del answer_options[answer_options.index(correct_answer)]  # delete the correct answer from d anaswer options
                    wrong_answers = random.sample(answer_options, 3)
                    answer_options = wrong_answers + [correct_answer]  # conactenate list with list
                    # print(answer_options)
                    random.shuffle(answer_options)
                    # print(answer_options)

                    # Write the question and answer options to the quiz file
                    question_file.write(f'{question_num + 1}. What is the capital of {state}?\n')
                    for index, option in enumerate(answer_options):
                        question_file.write(f'{"ABCD"[index]}. {option}\n')
                    question_file.write('\n')

                    # Write the correct answer to the answer key file
                    answer_file.write(f'{question_num + 1}. {"ABCD"[answer_options.index(correct_answer)]}\n')


if __name__ == '__main__':
    generate_random_quiz_files()

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

&lt;/div&gt;



&lt;p&gt;It's been a great journey of learning and practicing. Don’t worry if you are confused, everyone does. Now it is time for some practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Your task is to write a program that converts the dictionary to JSON format. After that, you will modify the code to use the JSON file instead.&lt;/li&gt;
&lt;li&gt;You will notice that there is a lot of nesting in the code which makes it less readable. Your task is to create smaller functions to get rid of the nesting.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;By now, you should have completed the exercises and gained practical experience. Remember, getting stuck is a normal part of the learning process. In this project, you learned how to generate random quiz files using the OS and random modules. You also implemented complex loops, used range functions, and mastered writing data to a file.&lt;/p&gt;

&lt;p&gt;This project has equipped you with essential skills that you can apply in various Python programming tasks. Continue to explore, practice, and refine your coding abilities.&lt;/p&gt;

&lt;p&gt;If you have any questions, want to connect, or just fancy a chat, feel free to reach out to me on &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://twitter.com/PraiseID3?s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to create a regex version of strip()</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Thu, 30 Nov 2023 20:35:36 +0000</pubDate>
      <link>https://dev.to/praise002/how-to-create-a-regex-version-of-strip-57c1</link>
      <guid>https://dev.to/praise002/how-to-create-a-regex-version-of-strip-57c1</guid>
      <description>&lt;h2&gt;
  
  
  Project 1: Practice Projects
&lt;/h2&gt;

&lt;p&gt;Welcome to the third project in this tutorial series. In this project, you will create a Regex version of &lt;code&gt;strip()&lt;/code&gt;. As usual, you will have examples and exercises to work on. Once you are done, you can compare your solutions by clicking &lt;a href="https://github.com/praise002/Regex/blob/master/projects/project-2/strong-password-detection.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Project A: Strong Password Detection
&lt;/h4&gt;

&lt;p&gt;This project is available in the project's &lt;a href="https://github.com/praise002/Regex/blob/master/projects/project-2/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;. Once you have completed it, return here to continue.&lt;/p&gt;

&lt;p&gt;Welcome back; now it's time to tackle Project B.&lt;br&gt;
In this project, you will create a Regex Version of strip().&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/praise002/find-common-typos-between-words-431n"&gt;Part 2&lt;/a&gt; in the series&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before starting this project, it's essential to have a good understanding of how &lt;a href="https://www.w3schools.com/python/ref_string_strip.asp#:~:text=The%20strip()%20method%20removes,any%20whitespaces%20will%20be%20removed." rel="noopener noreferrer"&gt;strip()&lt;/a&gt; works. Some developers use it frequently, while others seldom use it. Experiment with it to gain a clear idea of its functionality.&lt;/p&gt;
&lt;h2&gt;
  
  
  Write Code
&lt;/h2&gt;

&lt;p&gt;Now that you understand it, let us move on to writing code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a Function &lt;br&gt;
In this step, define a function called &lt;code&gt;regex_strip&lt;/code&gt; with two parameters: &lt;code&gt;input_string&lt;/code&gt; and &lt;code&gt;chars_to_remove&lt;/code&gt;, which has a default value of &lt;code&gt;None&lt;/code&gt;. This allows you to provide characters to remove if you wish, but if none are specified, it defaults to &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Step 2: Check for &lt;code&gt;chars_to_remove&lt;/code&gt; Being &lt;code&gt;None&lt;/code&gt;&lt;br&gt;
Here, you check if the &lt;code&gt;chars_to_remove&lt;/code&gt; variable is &lt;code&gt;None&lt;/code&gt;. If it is, you create a regex pattern that matches leading and trailing whitespace (similar to how &lt;code&gt;strip()&lt;/code&gt; works by default). This step ensures that if no characters are specified for removal, the function behaves like the standard &lt;code&gt;strip()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Create a Pattern&lt;br&gt;
You might notice that we create a pattern without using &lt;code&gt;re.compile()&lt;/code&gt;. The reason for this is that since it is a one time use, the performance gain is negligible. To learn more, click &lt;a href="https://www.quora.com/What-are-the-performance-implications-of-using-the-re-module-instead-of-compiled-regexes-in-Python#:~:text=Reusability%3A%20If%20you%20need%20to,text%20or%20within%20a%20loop." rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Step 4: Execute the Else Statement&lt;br&gt;
In this step, it checks whether &lt;code&gt;chars_to_remove&lt;/code&gt; is specified (not None). If it is, it executes the code inside the else block.&lt;/p&gt;

&lt;p&gt;Step 5: Substitute the Pattern&lt;br&gt;
Finally, you use &lt;code&gt;re.sub()&lt;/code&gt; to substitute any matching patterns with an empty string, effectively removing them from the &lt;code&gt;input_string&lt;/code&gt;.&lt;br&gt;
Here's the complete code:&lt;br&gt;
&lt;/p&gt;

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

def regex_strip(input_string, chars_to_remove=None):
    if chars_to_remove is None:
        # If chars_to_remove is not specified, remove leading and trailing whitespace
        pattern = r'^\s+|\s+$'

    else:
        # Escape characters that might be interpreted as regex metacharacters(.*?^$+)
        chars_to_remove = re.escape(chars_to_remove)
        # Create a pattern that matches characters specified in the second argument
        pattern = f'[{chars_to_remove}]+'  #['hello']+ 1 or more so it picks any matching pattern in the bracket

    return re.sub(pattern, '', input_string)

if __name__ == '__main__':
    input_string = input('Input a string: ')
    chars = input('Input a character to escape: ')

    # TEST
    # input_string = "ABCDEFHello, World!ABCDEF"
    # chars = "ABCDEF"

    # input_string = "   Hello, World!   "

    print(regex_strip(input_string, chars))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code provides you with a tool to strip specific characters from a given string using regular expressions. Feel free to experiment with different input strings and characters to remove to see how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise
&lt;/h3&gt;

&lt;p&gt;Here are some additional exercises to further practice your regex skills:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parsing CSV Data: Write a regex pattern to extract data from a CSV (Comma-Separated Values) file. Test it on a sample CSV file with different data.&lt;/li&gt;
&lt;li&gt;Extracting Hashtags from Social Media Posts: Create a regex pattern to extract hashtags from social media posts, such as #regex or #PythonProgramming.&lt;/li&gt;
&lt;li&gt;Parsing Log Files: Develop a regex pattern to extract specific information from log files, like timestamps, error codes, and messages.&lt;/li&gt;
&lt;li&gt;Validating ISBNs (International Standard Book Numbers): Write a regex pattern to validate ISBNs with different formats (e.g., ISBN-10 or ISBN-13). These exercises will help you apply your regex skills to real-world scenarios and expand your knowledge.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;In this project, you created a Regex version of strip(), building upon our previous skills. Keep practicing, experimenting, and applying regex patterns in various contexts to become more proficient.&lt;/p&gt;

&lt;p&gt;If you have any questions, want to connect, or just fancy a chat, feel free to reach out to me on &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://twitter.com/PraiseID3?s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>python</category>
      <category>strip</category>
    </item>
    <item>
      <title>Find common typos between words</title>
      <dc:creator>Praise Idowu</dc:creator>
      <pubDate>Thu, 23 Nov 2023 19:00:28 +0000</pubDate>
      <link>https://dev.to/praise002/find-common-typos-between-words-431n</link>
      <guid>https://dev.to/praise002/find-common-typos-between-words-431n</guid>
      <description>&lt;h2&gt;
  
  
  Project 1: Ideas for Similar Programs
&lt;/h2&gt;

&lt;p&gt;Welcome to the second project in this tutorial series. In this project, you are about to tackle four exciting problems. As always, you will be provided with examples and exercises to work on.&lt;/p&gt;

&lt;p&gt;Your goal in this project is to write more complex regular expressions to search, substitute, and manipulate text characters in strings.&lt;/p&gt;

&lt;p&gt;For access to the project README, click &lt;a href="https://github.com/praise002/Regex/tree/master/projects%2Fproject-1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Part 1 in the series&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before you start this project, you should roll up your sleeves and get some hands-on coding experience. Project A serves as a great warm-up, and it's quite similar to what we tackled in the previous project. Once you have completed it, click &lt;a href="https://github.com/praise002/Regex/blob/master/projects/project-1/website-urls.py" rel="noopener noreferrer"&gt;here&lt;/a&gt; to compare your solution. You will find all the necessary text files &lt;a href="https://github.com/praise002/Regex/blob/master/projects/project-1/txt-files/urls.txt" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have that clear, let us work on this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Project D: Find common typos such as multiple spaces between words, accidentally accidentally repeated words, or multiple exclamation marks at the end of sentences. Those are annoying!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Write Comments&lt;br&gt;
First, define a function called &lt;code&gt;remove_typos_in_word()&lt;/code&gt;. &lt;br&gt;
Second, write comments to explain each step. &lt;br&gt;
Third, call the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def remove_typos_in_word():
    # get the text off the clipboard

    # Define a regex pattern for multiple spaces between words
    # substitute multiple spaces with just a space

    # Define a regex pattern for accidentally repeated words
    # substitute it with just one word

    # Define a regex pattern for multiple exclamation marks at the end of sentences
    # substitute it with one exclamation mark
    # return the replaced text
    pass


if __name__ == '__main__':
    remove_typos_in_word()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Import Necessary Modules&lt;br&gt;
You already used these modules in the previous project, If you need a quick reminder, click &lt;a href="https://docs.google.com/document/d/1PuowyvZzjWWYdxjQOKcKoMtJVjkz5GOWGTvIuKvqPdE/edit?usp=drivesdk" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import re, pyperclip&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Paste Text from Clipboard&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def remove_typos_in_word():
    copied_text = pyperclip.paste()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Create a Regex Pattern for Multiple Spaces Between Words&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Define a regex pattern for multiple spaces between words
multiple_spaces_pattern = re.compile(r'\s{2,}')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Substitute Multiple Spaces with a Single Space and Store It in a &lt;code&gt;replaced_text&lt;/code&gt; Variable.&lt;br&gt;
Note: This regex can be improved. It seems to also remove new lines.&lt;/p&gt;

&lt;p&gt;To understand how &lt;code&gt;re.sub()&lt;/code&gt; works. Just hover your mouse at the function, and you will see the parameter it takes. It takes in a pattern, a replacement, and a string. The others are optional.&lt;/p&gt;

&lt;p&gt;Run your code to ensure that it works properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;replaced_text = re.sub(multiple_spaces_pattern, ' ', copied_text)
print(replaced_text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 6: Create Regex Patterns for the Remaining Two&lt;br&gt;
You might notice that we are not using the &lt;code&gt;copied_text&lt;/code&gt; variable anymore but rather accessing the &lt;code&gt;replaced_text&lt;/code&gt;. Can you guess why?&lt;/p&gt;

&lt;p&gt;The reason for this is that we want to continue working on the corrected text to apply additional regex patterns. This way, each correction doesn't interfere with the next one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Define a regex pattern for accidentally repeated words
    repeated_words_pattern = re.compile(r'(\b\w+\b)(\s+\1)+')
    replaced_text = re.sub(repeated_words_pattern, r'\1', replaced_text)
    print(replaced_text)

    # Define a regex pattern for multiple exclamation marks at the end of sentences
    multiple_exclamations_pattern = re.compile(r'!{2,}')
    replaced_text = re.sub(multiple_exclamations_pattern, '!', replaced_text)
    print(replaced_text)

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: The End Result&lt;br&gt;
This is the final form of the code. You return the &lt;code&gt;replaced_text&lt;/code&gt; variable, which now contains all the corrections. To access the result, you call the function and assign the returned value to the &lt;code&gt;replaced_text&lt;/code&gt; variable. Then, you copy it to the clipboard and print it in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import re, pyperclip

def remove_typos_in_word():
    copied_text = pyperclip.paste()

    # Define a regex pattern for multiple spaces between words
    multiple_spaces_pattern = re.compile(r'\s{2,}')
    # multiple_spaces_pattern = re.compile(r'(?&amp;lt;!\n)\s{2,}')
    replaced_text = re.sub(multiple_spaces_pattern, ' ', copied_text)
    # print(replaced_text)

    # Define a regex pattern for accidentally repeated words
    repeated_words_pattern = re.compile(r'(\b\w+\b)(\s+\1)+')
    replaced_text = re.sub(repeated_words_pattern, r'\1', replaced_text)
    # print(replaced_text)

    # Define a regex pattern for multiple exclamation marks at the end of sentences
    multiple_exclamations_pattern = re.compile(r'!{2,}')
    replaced_text = re.sub(multiple_exclamations_pattern, '!', replaced_text)
    # print(replaced_text)
    return replaced_text

if __name__ == '__main__':
    replaced_text = remove_typos_in_word()
    pyperclip.copy(replaced_text)
    print('Copied to clipboard.')
    print(replaced_text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exercise
&lt;/h3&gt;

&lt;p&gt;Now, it's your turn to tackle parts B and C in the "Ideas for Similar Programs." Once you have completed them, you can compare your solutions by clicking &lt;a href="https://github.com/praise002/Regex/tree/master/projects%2Fproject-1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: It's often more helpful to attempt the exercise before seeking a solution. Jumping straight to a solution won't help you learn. Best of luck.&lt;/p&gt;

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

&lt;p&gt;In this project, you created more complex regex patterns and implemented a search and replace functionality. Think about all the times you have encountered search and replace functionality; it's often powered by regex. Great work, and keep on learning.&lt;/p&gt;

&lt;p&gt;If you have any questions, want to connect, or just fancy a chat, feel free to reach out to me on &lt;a href="https://www.linkedin.com/in/praise-ifeoluwa-idowu-back-end-developer-django?utm_source=share&amp;amp;utm_campaign=share_via&amp;amp;utm_content=profile&amp;amp;utm_medium=android_app" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://twitter.com/PraiseID3?s=09" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
