Python, Visually Explained | Visually Explained | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Course Introduction

      3:53

    • 2.

      Getting Started with Colab

      3:21

    • 3.

      Numeric Operations

      2:18

    • 4.

      Numeric Operations - Guided Examples

      5:31

    • 5.

      Introduction to Data Types

      2:25

    • 6.

      Numeric Operations and Data Types - Exercise Solutions

      4:13

    • 7.

      Strings

      4:01

    • 8.

      Strings - Guided Examples

      7:08

    • 9.

      Strings - Exercise Solutions

      2:34

    • 10.

      Variables

      7:17

    • 11.

      Variables - Guided Examples

      7:29

    • 12.

      Variables - Exercise Solutions

      3:40

    • 13.

      Built-in Functions

      2:01

    • 14.

      Built-in Functions - Guided Examples

      3:27

    • 15.

      Built-in Functions - Exercise Solutions

      2:04

    • 16.

      Built-in Type Methods

      5:37

    • 17.

      Built-in Type Methods - Guided Examples

      2:58

    • 18.

      Built-in Type Methods - Exercise Solutions

      3:02

    • 19.

      Booleans and Comparison Operators

      3:59

    • 20.

      Booleans and Comparison Operators - Guided Examples

      4:45

    • 21.

      Booleans and Comparison Operators - Exercise Solutions

      5:03

    • 22.

      Conditionals

      6:14

    • 23.

      Conditionals - Guided Examples

      5:12

    • 24.

      Conditionals - Exercise Solutions

      2:43

    • 25.

      Lists

      2:38

    • 26.

      Lists - Guided Examples

      4:20

    • 27.

      Lists - Exercise Solutions

      4:50

    • 28.

      Tuples

      3:21

    • 29.

      Sets

      4:13

    • 30.

      Collections - Guided Examples

      5:59

    • 31.

      Collections - Exercise Solutions

      3:51

    • 32.

      For Loops

      8:59

    • 33.

      For Loops - Guided Examples

      7:31

    • 34.

      For Loops - Exercise Solutions

      10:13

    • 35.

      Dictionaries

      5:40

    • 36.

      Dictionaries - Guided Examples

      10:05

    • 37.

      Dictionaries - Exercise Solutions

      8:23

    • 38.

      User Input

      4:09

    • 39.

      Error Handling

      6:15

    • 40.

      User Input and Error Handling - Guided Examples

      4:00

    • 41.

      User Input and Error Handling - Exercise Solutions

      8:27

    • 42.

      While Loops

      8:18

    • 43.

      While Loops - Guided Examples

      5:19

    • 44.

      While Loops - Exercise Solutions

      7:00

    • 45.

      User-defined Functions

      9:41

    • 46.

      User-defined Functions - Guided Examples

      9:07

    • 47.

      User-defined Functions - Exercise Solutions

      9:00

    • 48.

      Namespace and Scope

      7:46

    • 49.

      Namespace and Scope - Guided Examples

      11:49

    • 50.

      Namespace and Scope - Exercise Solutions

      5:39

    • 51.

      Modules and Libraries

      10:34

    • 52.

      Modules and Libraries - Guided Examples

      7:59

    • 53.

      Python Standard Library - Exercise Solutions

      6:15

    • 54.

      Matplotlib - Exericse Solution

      3:11

    • 55.

      Pandas - Exercise Solution

      4:17

    • 56.

      Language Translator App - Project Introduction

      3:40

    • 57.

      Language Translator App - Project Solution

      13:18

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

149

Students

--

Projects

About This Class

Class Overview

Are you ready to master Python quickly and easily—without confusion or frustration? Python, Visually Explained is the ultimate beginner-friendly course that simplifies programming basics through clear, concise explanations and practical, real-world examples. Whether you’re new to programming or looking to enhance your skills, this course teaches you how to think like a coder and solve problems using Python, one of the most versatile and in-demand programming languages today.

Class Resources

All notebooks shown in lecture videos, exercise notebooks, and exercise solutions notebooks can be found on our course GitHub page: https://github.com/Visually-Explained/Python-Visually-Explained

What You Will Learn

By taking this course, you’ll gain hands-on experience and foundational knowledge in the following topics:

  • Getting Started with Google Colab: Your first step into Python, made easy.
  • Numeric Operations: Understand how numbers work in programming.
  • Data Types & Variables: Learn how to store and manipulate data like a pro.
  • Strings & Text Manipulation: Handle text and characters with confidence.
  • Built-in Functions & Methods: Simplify your code with Python’s built-in tools.
  • Booleans & Comparisons: Learn the logic behind decision-making in programming.
  • Conditionals & Loops: Write efficient programs that can make decisions and repeat tasks.
  • Data Structures (Lists, Tuples, Sets, and Dictionaries): Master Python’s most useful data structures.
  • User Input & Error Handling: Build interactive programs and handle errors like a pro.
  • Functions, Namespaces, and Scope: Create reusable code with confidence.
  • Modules & Libraries: Unlock Python’s full potential by using external libraries.
  • Visualization with Matplotlib & Data Analysis with Pandas: Work with real data and bring it to life.

Why You Should Take This Class

  • Clear and engaging explanations: Topics are broken down into bite-sized lessons, ensuring you never feel overwhelmed.
  • Hands-on exercises: Apply what you learn through practical, real-world coding challenges.
  • Beginner-friendly: No prior programming experience is required—perfect for complete beginners.
  • Flexible learning: Self-paced, so you can learn whenever and wherever it suits you.

By the end of this course, you’ll confidently write Python code, solve practical problems, visualize data, and perform basic data analysis. Whether you aim to start a new career, automate everyday tasks, or learn a valuable skill, this course will set you up for success.

Who This Class is For

This course is perfect for:

  • Complete beginners who have no prior experience with coding or Python.
  • Professionals or students looking to build foundational programming skills.
  • Anyone interested in learning Python for automation, data analysis, or career development.
    No prior coding knowledge is required to take this class.

Materials/Resources

To take this course, you will need:

  • A computer with internet access.
  • A Google account to use Google Colab (free online coding environment).
  • No additional software or setup is required.

Resources provided in the course:

  • Example code snippets.
  • Step-by-step exercises.
  • Templates and starter files to practice along with the lessons.

Meet Your Teacher

Teacher Profile Image

Visually Explained

Visual Learning for Complex Topics

Teacher

At Visually Explained, we believe that learning complex topics becomes effortless when they're made easy to see and simple to understand. Through clear visual explanations--using illustrations, diagrams, and intuitive examples--we break down challenging concepts into something tangible and approachable. Our courses are designed for visual learners who thrive on seeing how things work, replacing dense text and jargon with highly visual content that simplifies even the toughest topics. With practical exercises to reinforce real-world application, we ensure learners not only grasp concepts but can apply them with confidence. Visually Explained is something we--Sebastien and Ally--created together, and below you'll get to know us and the passion we bring to every course!

See full profile

Level: Beginner

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Course Introduction: Welcome to PyTon Visually Explain a course designed to teach you programming using PyTon. In this course, we use visual representations to illustrate concepts and make programming accessible. By taking this course, you learn the fundamentals of programming and use those concepts to solve real world problems. To support you on your PTN journey, you'll have two experienced mentors by your side. My name is Sebastian. I'm a finance professor at the University of Wisconsin Madison. I've been using PyTon extensively for many years, both for my academic research and in the classroom. And I'm Ali, the teaching assistant for this course. I hold a double major in computer science and finance, also from the University of Wisconsin Madison. Whether you're a complete beginner or have some experience programming in other languages, this course will teach you valuable skills. Beginners will get the chance to learn the basics comfortably as we don't assume any prior programming knowledge. The first lectures of this course introduce fundamental concepts such as variable assignments. We then build on those foundations to study more complex topics like for loops. Finally, we'll show you how to unlock new capabilities by tapping into Python libraries, giving you endless tools to solve problems from creating graphs to performing language translation and much more. This modular structure is also great for experienced programmers interested in specific aspects of the Python language. You can jump directly to topics of interest and familiarize yourself with the Python syntax. We have developed this course to be clear and concise. We respect your time as a learner and want to help you learn concepts efficiently. Each concept in this course, has its own dedicated module with several videos. Every module kicks off with one or two introductory videos, giving you a basic understanding of the concept through visual explanations and code examples. Then we dive deeper with videos that explore more advanced use cases. In these videos, you'll join Jamie and Pike on their hiking Adventures, where they encounter problems that we solve in Python. Doing so allows us to see how concepts we've learned can be applied. Then to deepen your understanding of the concepts, we provide exercise notebooks that you can work on independently. These exercises will allow you to master each topic and often introduce new related ideas. Following each exercise workbook is a video walking through the solutions to the exercises. These videos break down each problem step by step using clear visuals to support your learning. Every module has an associated file on our course Github page. This file contains links to notebooks we use in the videos, exercise notebooks, and extra learning resources. Feel free to explore the resources and follow along with the videos in the provided notebooks. Finally, at the end of the course, you will work on a project where you apply your new programming skills to create a language translator application. I'm a little biased, but it's a lot of fun. We're excited to have you on this journey. No matter where you're starting from, this course is designed to make programming concepts intuitive, practical, and enjoyable. Let's get started. 2. Getting Started with Colab: This video, we will introduce the Python coding environment used in this course. It's called Google Collaboratory or Colab. Colab is a great environment for learning programming because it's free and cloud based, meaning you can access it from any computer without installing any software. Setting up Colab is very easy. All you need is a Google account. If you use Gmail, Google Drive, or Google Calendar, good news. You already have an account. But if you don't, you can create an account for free by going to accounts google.com slash SINAP. Once you've signed up, navigate to your Google Drive where you'll be able to create your first Colab notebook. To create a new Notebook, click the New button. Go to Me and you may or may not see the Google Colaboratory option. If you do not see Colab as an option, that means we need to install it. Click Connect More Apps and search Collaboratory. Then click on Collaboratory and install it. You will be presented with a few permission dialogues before Colab is installed. Awesome. Now let's create a notebook and explore the basic functionality of Colab. Every notebook is divided into cells where we can write code or other text. To create a new cell, hover over the top or bottom edge of an existing cell. Here, we see that there are two types of cells. Code cells, like the one that already exists, are where we write our Python code. Text cells are for anything that isn't code. Optionally, we can format cells using Markdown, which we won't cover in this course. If you want to learn more about Markdown, there is a helpful link on the GitHub page for this module. Additionally, we can change the order of cells using the arrows and remove cells by clicking the trash icon. Eight. While you might want to create notebooks from scratch for your own projects, in this course, we will provide notebooks for every video. You can access every notebook through the notebook Links page in this module. This link will take you to a GitHub page where you'll find a file for each module with links to notebooks and other relevant information. When you click a Notebook link, you will be taken to a read only copy of the Notebook. To make your own copy, click the copy to drive button in the toolbar and Colab will create a copy in a new tab. You now own this copy of the Notebook and it is saved to your Google Drive. This means that you can edit the cells and the notebook name. To view the list of your Colab notebooks, click the logo in the upper left corner to go to Google Drive. Alternatively, you can access the course notebooks that you copy to your drive in the Colab notebooks folder. Great. These are all the features of Colab that we need to get started. As we progress through this course, we'll explore Clob's functionality a lot more. So don't worry if this interface seems a little intimidating right now. When we tackle our first topic, we will learn how to write and run code in a notebook. And with that, let's dive in. 3. Numeric Operations: Welcome to the first programming concept of this course numeric operators. In this video, we will see how to use numeric operators to perform basic mathematical operations in PyTon. The concepts covered in this video are quite simple. Which is a good thing as it will allow us to gently familiarize ourselves with the Google Colab environment. In Bton, numeric operators such as plus, minus star and slash can perform mathematical operations on numbers much like you learned in grade school. For example, if we are interested in calculating the sum of two and three, we can write two plus three in a code cell. Then to evaluate the expression, we must instruct Python to execute the code. In Google Colab, this is done by clicking the Run button on the left of the code cell or by pressing the keys Control plus Enter or Command plus return depending on your operating system. Congratulations. You have now executed your very first line of code. Unsurprisingly, PyTon reports that the value of two plus three is five. Similarly, if we want to subtract three from two, we use the subtraction operator minus to multiply two and three, we use the multiplication operator star and to divide two by three, we use the division operator. In each cases, when we run the code cells, we obtain the expected answers. Great. We have now run our first few lines of Byton code. That was easy, wasn't it? In the next video, we will see a few examples of use cases for the operators we covered in this video and we'll introduce a few more operators. 4. Numeric Operations - Guided Examples: Jamie is excited about her upcoming weekend hike. But before she ventures into the wilderness, she must plan accordingly. In particular, she must determine how many miles she will hike, how long she will be gone, how much water to carry, and so on. Miles, time, and ounces of water are all about numbers. And since Matt is not Jamie's strong suit, she will ask Bike to perform a few calculations for her. One of Jamie's health goal is to walk at least 10,000 steps daily. She'd like to meet that goal during our hike. To meet our objective, how many miles long should our hike be given that our average stride length is 2.5 feet. While Pike computes the answer, let's see if we can solve the problem using Piton. First, to fight the distance in feet Jamie needs to hike, we must multiply her step goal 10,000 by our stride length, 2.5 feet. Executing the cell, we obtain a result of 25,000 feet. Now, let's convert this quantity into miles. We do this by dividing our previous result by 5,280 the number of feet per mile. Executing the cell, we obtain 4.73 miles, and so does Pike. Based on that information, Pike suggests to hike a local trail called the roller coaster. However, it cautions Jamie that this trail features some challenging climb with a total of 500 feet of elevation gain. From Jamie's perspective, though, elevation gains make hiking a trail exponentially more fun. Because Jamie likes to quantify all aspects of her adventures, she asks Pike to calculate how many units of fun she will have hiking the roller coaster trail. According to her, the fun of a hike is calculated as the elevation gain squared plus a baseline of 1,000 units of fun for simply getting outside. Let's make the calculation in the notebook. To implement the formula, we need to square the elevation gain. In Pyton, the exponent operator is the double star. We complete the expression by adding an extra 1,000 units of fun for just getting outside. When we execute the cell, we obtain 251,000 units of fun. And so does Pike. That's all good, but with lots of fun comes lots of responsibilities. Jamie must ensure she stays well hydrated during the hike. From previous experience, she knows that a hike that long will require 40 ounces of water. To carry water, Jamie has 512 ounce bottles. She is interested in finding out the number of bottles that need to be filled, and if applicable, she wants to know the volume that should be added to the last bottle in order to have a total of 40 ounces of water. We can, of course, find this quantity using the regular division operator. By calculating 40/12, we obtain 3.33. This indicates that Jamie needs three full bottles and a fourth bottle filled to one third of its capacity or 4 ounces. This method works, but PyTon provides two other operators that make this calculation just a bit easier, the floor division and modulus operators. The floor division operator returns the number of times the divisor, in this case, 12 goes evenly into the dividend, in this case, 40. In our example, the expression yields a results of three, indicating that Jimmy requires three full bottles of water. Note that the floor division operator yields the integer part of the regular division's outcome, discarding any fractional component. Awesome. Let's now talk about the modulus operator. The modulus operator returns the remainder or the leftovers after floor division. In our example, the leftovers after floor division is four. And look at that. Pike agrees with our assessment. We now know all of PyTon's arithmetic operators. In the next video, we'll gain some practice with those numeric operations. 5. Introduction to Data Types: Previous video, we wrote multiple numbers in our notebook. Some were numbers, and others were decimal numbers. The Python language makes a formal distinction between these two types of numeric values. In this video, we'll explore this distinction as we introduce the notion of datatype. Whole numbers, that is any positive or negative number without a fractional component are called integers in programming. For their part, decimal numbers, that is any positive or negative number with a fractional component, are called floats. Let's confirm that Piton indeed makes a distinction between these two types of numbers. To verify the existence of that distinction, we will use the built in function type. We will discuss built in functions in detail in a future video. For now, let's take as given that writing type, followed by a number between parentheses, instruct PyTon to output whether the number is an integer or a float. For example, if we write the number 13 inside parentheses and execute the cell, PyTon outputs int this means that the value 13 is of the integer data type. Similarly, if we write the number 3.14 15 inside the parentheses, we obtain float. In PyTon, the distinction between integers and floats is somewhat technical. There are contexts where this distinction matters, but for the applications we consider in this course, it won't really matter. Important general concept to take away from this video is the notion of data type. BTN can represent various types of data, including integers and float, but also several more. Over the course of these lectures, we'll cover many more data types and explore their use. But before we go there, let's solve a few exercises on integers and floats to gain some practice. 6. Numeric Operations and Data Types - Exercise Solutions: In this workbook, you practiced using Python's numeric operators and the type function. Let's go through the solutions. To solve exercise one, part A, we can use the multiplication operator. Just multiply the number of loaves by the weight of flour per loaf and then by the cost per kilo. The owner's total cost is $12.65. We can also check the type of our cost using the type function. Because of the decimal places, we would expect $12.65 to be afloat. And Python agrees. For exercise two, we can find the total cook time for the 200 cookies by using parentheses to group terms together. Because we have two ovens with a 25 cookie capacity, we can multiply 25 by two to get the total cookie capacity. Then we divide the 200 cookies we need to bake by this expression, grouping it with parentheses to ensure the correct order of operations. This results in the number of batches we need to cook in the oven. Finally, we can multiply this expression by 15 minutes to get the total time. Again, we use parentheses to ensure proper order of operations. Executing the cell, we get that it will take 60 minutes to bake all the cookies. If we do not use parentheses, we will get 240, which is incorrect. Again, we can check the type of R result using the type function. 60.0 is a float because it has a decimal component, even though the decimal component is zero. Moving to exercise three, we can calculate the number of full batches using the floor division operator. 250 grams of chocolate chips, floor divided by 40 grams per batch, results in six. We can calculate the leftover grams of chocolate chips with the modulus operator. When we have 250 grams of chocolate chips and need 40 grams per batch, we have 10 grams leftover after six batches. Similarly, in Part B, we can use the floor division operator to calculate that if each pastry needs 37 grams of dough and we have 500 grams of dough, we can make 13 pastries. Using the modulus operator, we can also see that there will be 19 grams of dough leftover. Great. In exercise four, we can capture the fact that the yeast doubles in mass every hour with the exponent operator. If the yeast is allowed to grow for 6 hours, we raise two to the power of six. Then we multiply that by the starting grams of yeast three to get the result of 192 grams after 6 hours. Finally, in exercise five, to calculate the weight of the flour, we simply multiply 20 by 23 to get 460. Next, to calculate the weight of the sugar, we can use the exponent operator to find the square root of the weight of the flour, 460 to get 21.45. Then, we use the modulus operator to find the remainder of the total flour and sugar divided by 42, which results in 19.45. Finally, the total weight is the sum of the three ingredients and is 500.9. In Part B, we can reuse the total weight of the ingredients and utilize regular division to see that the owner can make 8.04 batches with 62.3 grams of ingredients per batch. However, because the owner cannot make 0.04 of a batch, we should round down. We can do this using the floor division operator to retrieve only the whole number component of the division result, which is eight. Great. Now that you understand numeric operations and the type function, we are ready to start exploring another of Python's data types strings. 7. Strings: So far, in our journey through PyTn's data type, we have covered integers and flows, which are the foundation of numeric representation in programming. Moreover, we have seen several operators that perform mathematical operations on numeric values. Now, let's shift gear and venture into the world of textual data. In this video, we'll introduce you to strings, an essential data type used to represent text in PyTon. Strings open up a whole new world of possibilities in programming from processing user inputs, to creating large language models. By the end of this lesson, you'll know how to create and manipulate strings in Python. In programming, being able to represent textual data is often useful. For example, a grade assignment program may need to represent the letter A. Similarly, a spell checker program might need to represent the contents of long text like the Odyssey. In Python, textual data, such as a single letter or the Odyssey poem are managed using strings. To create a string, we enclose the desired characters between single or double quotation marks. For example, to represent the letter A, we can type the letter A in a code cell and surround it with single quotation marks as follows. Similarly, to represent the entire content of the Odyssey poem, we can bracket the book's content with single or double quotation marks as follows. Note that the quotes are not part of the string itself. They are there to delimit where the string begins and ends. Also, note that strings can be used to represent numbers and other special characters. Wait a minute. What did I just say? Strings can be used to represent numbers. So why do we need integers and floats in the first place? Aren't string enough by themselves? The answer is no. As we are about to see, Biton makes an important distinction between numbers that are expressed as integers or floats and numbers that are expressed as strings. For example, let's say that we want to evaluate the sum of one and two. If we represent these numbers using integers or floats, we obtain the number three as expected. But if we represent these numbers using strings and evaluate the expression, what do we get? We got 12. Wow. That's some new age mathematics right there. What happened? Well, as you may have guessed, when we work with strings, the plus operator means something different than when we work with numeric values. With numeric values, the plus operator performs an addition. With strings, the plus operator ties strings together. As this example shows, data types can influence the behavior of a given operator. This in turn creates an important distinction between various datatypes. In Piton, data types determine the behavior of the operators we use. In the next video, we will explore some operations that are specific to strings. 8. Strings - Guided Examples: Jamie and Pike have just started their hike on the rugged Roller Coaster trail. Despite its name, the first part of the roller coaster trail is well maintained and mostly flat. Jamie relaxes as she enjoys the mountain scenery and the fresh smell of pine trees. Wonderful. However, half an hour into the hike, the Roller Coaster trail takes back its name. Indeed, in front of Jamie and Pike looms a 15 foot deep ravine splitting the trail. To get across, our two hikers will need the rope they fortunately brought. While Jamie and Pike manipulate robes to solve their problem, we will study how manipulating piton strings can help programmers tackle analogous challenges. Before initiating the descent, Jamie asks Pike to scan the rope for defects. Safety first, Pike carefully checks the rope and represents the scan results using characters. If a given foot of rope is defect free, it is represented by the dash character. However, if the scan reveals a defect, that foot of the rope is represented by the star character. Let's represent the results of Pike scan in Piton using a string. Unfortunately, as you can see, there is a defect in the rope. Jamie should have checked it before leaving. But now that she's aware of it, she wants to find out exactly where the defect is located on the rope. Since in our code, each character represents 1 ft of rope, we can visually inspect the string and see that the defect is the ninth character. That is, it is on the ninth foot of the rope. Let's see if Biton agrees with our visual inspection. When we know the position of a character in a string, we can ask Python to output that character by indexing the string. To index a string, we must append a pair of brackets at the end of it and provide the position of the desired character in between the brackets. The number we write in between the brackets is called the index of the character. So, surely, when we execute this code, we will obtain the character star, right? Oh, well, that's unexpected. Why do we get a dash character? The reason is that in Bton, the characters of a string are index starting from zero and not from one. When we access the character located at index nine, we actually pull the tenth character of the string, not the ninth. We can get the defect character as output by changing our index to eight and re running our cell. All right. Now that Jimmy knows where the defect is, she wants to remove it from the rope. Always a good helper, Pike slices the rope before and after the defect and is left with two defect free pieces of rope. We can achieve a similar result in Python by slicing the string. But while indexing returns a single character, slicing allows us to retrieve multiple adjacent characters. To slice a string, we start by appending a pair of brackets at the end of the string. Then between the brackets, we first write the index of the first character we want to retrieve. For example, to get the first defect free section of the road, we start by writing zero. We follow that first index with a column. Then we specify the index of the last character we want plus one. This means that in our example, to obtain the first characters of the string up to and excluding the defect, we write eight. When slicing a string, the character associated with the upper index is not return. I know. It can be a bit confusing, but you'll get the opportunity to practice in the next video. For now, let's confirm that this piece of code gives us what we want. When we run our code, we indeed obtain the first eight characters of the string. Similarly, we can retrieve the other defect free rope section by slicing the string from index nine to index 19. Again, we achieve this by writing 20 after the colon. Awesome. Jamie and Pike got rid of the defect. Unfortunately, they are now stuck with two pieces of rope that are too short to cross the ravine. That's when Pike gets the brilliant idea to tie the two pieces together. We can achieve an analogous result in PyTon by using the plus operator. Indeed, as we saw in the previous video, the plus operator can be used to join strings. In our current example, if we copy our previous two string slices in a new cell and tie plus in between them, Piton will tie them together. Note that in programming, the operation of joining two or more strings together is called concatenation, and the plus sign is called a concatenation operator. Awesome. Now that the two ropes are tied together, Jamie must verify if the joint rope is still at least 15 feet long. No worries if you do not have laser eyes or the patience to count the characters. Biton has a built in function called N that can do the heavy lifting for us. The LN function can be used to determine the length of a string, much like the type function could be used to determine the type of a number. To use the NN function, simply type the strings in between the parentheses and execute the code. We obtain that our string is 19 characters long, which means that the rope is 19 foot long, and that is enough rope to cross the ravine. Our two hikers can move on with their hike. But on our side, before we move on with our Python journey, let's take a few minutes to practice manipulating strings. 9. Strings - Exercise Solutions: In this workbook, you practiced string operations and also learned a few more useful string related concepts. Let's discuss the solutions. To solve exercise one, we need to be mindful of the two ways of creating strings. In Part A, our string contains an apostrophe, so we must create the string using double quotes. Otherwise, Python thinks the apostrophe is part of the string delimiters, and we will get an error instead of a string. However, the opposite is true in Part B. Because our string contains double quotes, we must create the string with single quotes. If we do use double quotes to try to create the string, we will get an error since Python assumes that the double quotes are part of the string delmeters. To solve Exercise two part A, we use indexing to retrieve the G from ground beef. Starting from index zero, the G is the seventh character, so we specify seven between the brackets. This successfully retrieves G from our ingredients string. In part B, we can get the slice ground beef by specifying the index range seven to 20. Remember, the end index is exclusive. So because we want index 19 to be included in our string, we specify the ending index as 20. Then in Part C, we can use shorthand slicing notation to retrieve two slices of our ingredients string. First, because the slice onion starts at index zero, we don't need to specify that index. We can simply write colon five in between brackets to access the onion slice. Next, we can get the slice from spices to the end of the string by writing the starting index 22, followed by a colon. We do not need to specify the ending index since we want every index until the end of the string included in our slice. Then in exercise three, part A, we can use the concatenation operator to join multiple strings together on a single line of code. In Part B, we can use the star operator to quickly concatenate garlic clove twice to our ingredients string. Finally, in Part C, we can use the len function to measure the final length of our ingredients string, which is 143 characters. Great. Now you have a solid understanding of strings and the operations that we can perform on them. In the next video, we will tackle one of the most important and foundational concepts in programming, variables. 10. Variables: In previous videos, we have seen how to manipulate three fundamental data types, integers, loads, and strings. This was a lot of fun, but like me, you may have found that constantly copy and pasting values was tedious. In this video, we will see how to manage values more efficiently using variables. So what are variables exactly? In a programming context, you can think of variables as storage containers that can hold data. The data we store in variables can be of any type, including integers, floats and strings. When creating a variable, we must give it a unique name. Think of this name as a label for the container. Using a label that describes the value we store is a good idea, since it makes it easier to refer to it later. Let's see how variables work through an example. Suppose that we want to store the string that represents Jamie's rope in a variable. This can be done by first preceding the string with the symbol equal. In PyTon, the equal symbol is known as the assignment operator. It tells PTN that we want to put or assign the data on the right hand side of the equal sign in some storage space. To complete the assignment, we must type a variable name on the left hand side of the equal sign. For example, we can type X, running the cell, we see that the code executed without issue from the green checkmark. Note that when assigning a value to a variable, the value itself is not reported in the output box. To output the content of a variable, simply type the variable's name on the last line of the cell. Now, let's talk about our variable name choice. It is a valid name in the sense that this code executed without issue, but X is not very descriptive of what is in the storage container. So let's pick a more descriptive variable name. Here, I suggest that rope is a better variable name since it directly evokes what we store in the variable. When we run our program, the code executes successfully, which tells us that rope is also a valued variable name. This is great. With this statement, we have been able to assign our string to the variable rope. Now that we know how to create variables, let's explore how to use them. In general, we can manipulate variables the same way we can manipulate the values they store. Remember how we manipulated strings in the previous videos? We can still perform all those operations when our data is stored in a variable. For example, we can index the content of the variable rope by appending brackets at the end of the variable name and writing the index of the character we are interested in between the brackets. Similarly, we can slice the content of rope using index range notation. If we want, we can even create new variables to hold the string slices. And to tie the left rope and the right rope together, simply use the concatenation operator with the two variable names. Awesome. We now know how to manipulate variables. But before we move on, let's say a few more things about variable names. At this point, you might be under the impression that any variable name is suitable. However, this is not the case. There are a few constraints we must be aware of. Let's dive into it. If you recall, our concatenated rope string has a length of 19 characters. So if we wanted to assign it to a variable, it might be tempting to assign it to a variable named 19 foot rope. Let's try to do that. Whoop. Hmm. That doesn't seem to work. Why not? Well, that's because when naming variables, we must follow four rules. First, variable names cannot start with numbers. Clearly, the variable name 19 foot rope violates this rule. That being said, besides the first character, numbers can be included in any other part of the variable name, including the last character. For example, variable names like My var two and my second var are valid. This means that to fix the error, we could use a name like 19 foot rope or rope of 19 feet instead. As expected, these are valid variable names. But let's still discuss the other three rules. The second rule says that letters, numbers, and underscores are the only characters that we can use in a variable name. Clearly, our variable name 19 foot rope does follow this rule. But names like my Star var or M var exclamation point or my var, in two words, do not. The name myvar in two words also violates the third rule. Spaces are not allowed. Because variable names cannot contain spaces, programmers commonly separate words with the underscore character for readability. That's what we did with our variable name, 19 foot rope. Finally, the fourth rule we must be aware of is that variable names are case sensitive. This means that Python will recognize 19 foot rope as a different variable than 19 foot rope where we capitalize the first letter of each word. Great. Variables are an essential programming tool that will be key as we move into more complex programming. In the next video, we'll explore an application where using variables turns out to be quite helpful. 11. Variables - Guided Examples: Jamie and Pike are progressing quickly on the roller coaster trail despite the blazing sun and rising temperatures. As they pass the 1.5 mile mark, Jamie takes a gullp of water and finishes up her first bottle. This makes her wonder, does she have enough water to keep drinking at that rate for the remainder of the hike? Pike offers to help calculate our water consumption rate in terms of ounces of water per mile hike. We'll do this calculation in PyTon using variables to help us organize the data. First, let's create variables to store the number of miles Jimmy has hiked so far, 1.5, and the number of ounces of water she has drank. 12. Let's also create variables for the length of the hike, 4.73 miles and for the volume of water she has with her, 40 ounces. Using the first two variable assignments, we can determine the current rate at which Jamie is drinking water. We must simply take the ratio of the water she has consumed to the distance she has hiked. To keep track of the result, let's assign it to the variable current CR, which stands for current consumption rate. Then let's calculate the maximum consumption rate that Jamie can afford throughout the hike using the last two variables. Let's store that information in the variable MAX CR, which stands for maximum consumption rate. By executing these cells, we find that Jamie's current consumption rate is 8 ounces/mile, and the maximum consumption rate she can afford is 8.46 ounces/mile. Of course, Pike gets the same result, but Jamie is a bit confused by how he delivers the answer. Without context, it is difficult for Jamie to know what these numbers mean. In PyTon an easy way to provide context for a program's output is to use strings. So let's create two new string variables to contextualize Jamie's current water consumption and maximum water consumption. Great. Now let's see how we can use those strings jointly with the values to provide some context. We may be tempted to concatenate the description text and the output value. However, if we do that, we receive an error message telling us that PyTon cannot concatenate a string and a float. Well, if we think about it, we know that the plus operator has a different meaning depending on whether it is used with numbers or with strings. When presented with both a string and a number, Pyton is confused about what to do. Thankfully, as we saw in the previous video, it is possible to represent numbers as strings. So if we knew how to convert current consumption rate from a numeric value to a string, we could perform the concatenation. Let's see how to do that. In programming, the operation of converting a data type into another data type is called typecasting. In particular, we can use the built in function STR to convert or cast the variable current consumption rate from a float to a string. That is, we can type STR and then enclose our calculation in parentheses to perform the numeric to string conversion. If we execute the cell, we see that the value associated with the current consumption rate is now written between single quotes, which means that we have successfully converted the float to a string. With the value converted, you can see that the concatenation now works. Similarly, we can apply the string casting function to the maximum consumption rate calculation and concatenate it with max text. We now obtain a much more informative output, as I'm sure you agree. Awesome. Jamie looks to be on track with our water consumption and can continue drinking water at her current rate. Converting numeric values such as floats and integers to strings is one of many casting operations we can perform in Piton. It is also the most straightforward casting operation, since, as we have seen in the previous video, any numeric value can be represented as a string. But this begs the question, can we do the opposite? Can we convert strings into integers and floats? The answer here is a bit more nuanced. When a number is represented as a string, the functions int and float can be used to convert the string into an integer or a float respectively. For example, using the float function, we can cast the current consumption rate and maximum consumption rate variables from strings back to floats. Note that the single quotation marks around the values have disappeared, indicating that the values are numeric and not strings. But be careful. Not every string can be cast into a float or an integer. For example, we cannot convert our entire current consumption sentence into a float. That doesn't make sense. Finally, using the float and in functions, it is also possible to cast integers into floats and floats into integers. For example, if we assign the float version of the current consumption rate to its own variable, we can then use the int function to convert the value into an integer. However, be mindful that when you cast the flow to an integer, the decimal portion of the number is lost. For example, casting total miles to an integer results in the value four. We indeed lost the decimal portion during the cast operation. Alright, I know this was a lot of information. To help you remember, we've prepared the following summary table describing the casting rules. For your reference, this table is reproduced at the beginning of the exercise workbook that follows this video. Awesome. We now know how to store and access information using variables. Moreover, we've learned how to manipulate data types. In the next video, we will practice using variables and typecasting. 12. Variables - Exercise Solutions: In this workbook, you got the chance to practice using variables to solve problems. You also learned several more concepts related to variables which make them even more of a useful programming tool. Let's go through the solutions. First, in exercise one, we revisited a concept that was discussed in the previous guided examples video. That is, Python does not allow us to concatenate strings and numeric data. In part A, we created two variables to store the number of Blaze wins 13 and the number of Titans wins 12. In Par B, we created two more variables to store the description strings, Blaze wins and Titan wins. Then we cast both numeric variables, Blaze wins and Titans wins to strings using the STR function. Doing so allows us to avoid an error and produces the desired string output. In Part C, we introduce the concept of F strings. F strings are great for embedding variables into strings more naturally than by using concatenation and casting numeric values to strings. Here, we can either reuse the square text variables from Part B in our string like this, or we can directly type out the score text like this. Next, in exercise two, we use the concept of multiple assignments to create variables for each of the team's scores and set them all to zero in a single line of code. We can see from the outputted value that both variables have indeed been assigned the value zero. Moving to exercise three, we can take advantage of the plus equals assignment operator that Python provides to add values to existing variables more efficiently. For each quarter, we add the points scored to the corresponding team's score variables. After a close game, the final score of the Titans is 112, while the final score of the Blaze is 108. It looks like the Titans have won the championship. Finally, in exercise four, we encounter a custom metric courtesy of your coworker called player magic. We can determine the final value of the player magic variable by calculating the variable value after each line. After line one, player magic is ten. In line two, we apply the modulus assignment operator. This line of code is saying that player magic is now equal to the previous value of player magic ten modulus two. Because two divides ten evenly, ten modulus two is zero. So after line two, player magic is zero. On line three, we add 23 to the previous player magic value, zero to get player magic as equal to 23 after line three. Line four applies the division assignment operator. This divides player magic, which is 23 by five to get 4.6. Then on line five, we apply the floor division assignment operator, which removes the decimal component from 4.6, leaving player magic equal to four at the end of line five. Online six, we multiply four by nine to get player magic equal to 36. Line seven tells us we need to subtract 34 from the previous player magic value 36 to get two. Finally, on line eight, we apply the exponent assignment operator to set player magic equal to two to the power of three or eight. And it looks like Python agrees with our assessment. Great. Now that you are familiar with how variables work and how to use them in more advanced contexts, we can move on to the next topic, built in functions. 13. Built-in Functions: In previous videos, we've used several of BTon's built in functions to perform various tasks. While in those videos, we explain how to use a few of the built in functions. We have postponed a rigorous discussion of this concept until now. So let's dig deeper together into this important notion. In PTN, built in functions are predefined shortcuts that allow programmers to perform specific tasks with minimal effort. These functions accept certain inputs known as arguments on which they perform some operations. Once the operations are performed, a function typically produces an output, which is referred to as the return value. Take our previous usage of the type function as an example. We gave the function the variable total miles as an argument, and it returned the variable type float. Note that the process by which the function type gets from total miles to float is not explicitly given. In a way, you can think of a built in function as a little black box. A black box? That doesn't sound like a good thing. Well, it turns out that it's actually a very useful feature of built in functions. Because we can use built in functions without learning their inner workings, we can save time and effort making our programming tasks easier and quicker to complete. As you can see, built in functions are very helpful in PyTN. In the next video, we'll expand our coding toolkit by introducing a few new built in function and exploring use cases together. I'll see you there. 14. Built-in Functions - Guided Examples: Jamie and Pike have reached the second major obstacle of their hike, a daunting uphill stretch that even experienced hikers find difficult. While taking a break from the challenging ascent, Jamie wonders what total elevation change she'll experience during the hike. Pike reminds her that the elevation gain is 500 feet, and of course, the elevation loss is also 500 feet. To find the total elevation change, we must add the elevation gain and the absolute value of the elevation loss. In Pyton the ABS function has been designed to do just that. Adding the absolute value of elevation loss to elevation gain, we find a total elevation change of 1,000 feet as you probably expected. And that's also the number that Pike reports. But again, Jamie would like a bit more context around the output. In a previous video, we added context to our output by casting numerical results to string and concatenating a descriptive label. This worked, but there is a better way to do it. In PyTon, the print built in function makes it easy to display values in the output box. The key advantage of the print function is that it handles typecasting and concatenation for us. Let's see how to use this function. For convenience, let's first assign the result of our calculation to a variable. Then let's create a label variable and assign it to string total elevation change. All right. We are now ready to call the print function. This function has an interesting feature that we have not seen yet. It can handle multiple arguments. To input multiple arguments in a function, we write them between the parentheses and separate them with a comma. When we execute the cell, the print function writes to the output box the value of its first argument, followed by the value of its second argument. We should know that the order of the inputs matters. If we flip the order in the function call, we also flip the display order in the output box. Great. Now, Jamie and Pike are all rested up and ready to tackle the steep ascent. Before we follow them, let's make a few final remarks about built in functions. The print function is just one of many built in functions admitting multiple inputs. For example, we can use the Max built in function to determine the largest number out of the argument one, four, two, six, and five as follows. For your information, ITN has around 70 built in functions ready to assist you with common operations. You'll get the chance to explore a few more of those built in function in the exercises that follow. 15. Built-in Functions - Exercise Solutions: In this workbook, you explored several of Python's built in functions. Let's break down the solutions. In Exercise one, we can output Alex's workout plan with the correct formatting by utilizing the escape sequences, backslash N and backslash T to create new lines and tabs respectively. After the header and each day's workout, we insert a new line character which tells Python to move the following text onto the next line. We also add the tab escape sequenced before each day's workout line to tell Python to indent the following text. Our result is a well formatted workout plan. Next, in exercise two, we can determine the absolute value of the difference between today's and yesterday's step counts by using the ABS function. Because we are finding the absolute difference, the order in which we subtract the two step values makes no difference to our final result. We find that the difference between the two days step counts is 3,050 in either arrangement. In exercise three, we can use the max function to identify the most number of steps Alex took in the last seven days. By passing the seven step counts as arguments to the MAX function, we obtain the greatest number of steps Alex took was 15,400. Then to solve exercise four, we invoke the Min function to find Alex's fastest hundred meter time. Similar to how we use the Max function, we pass the five times in as arguments and get that 13.87 was Alex's fastest time. Finally, in Exercise five, we calculate the average minutes that Alex plans to exercise per day using the standard average calculation. Then we pass our average minutes variable along with one as arguments to the round function. This tells Python that we would like average minutes to be rounded to the first decimal place. Awesome. Now you have gotten the chance to use several Python's built in functions. In the next several videos, we will be exploring some more built in operations that Python provides. 16. Built-in Type Methods: When Pike reported the total elevation change in a previous video, he overlooked capitalizing the first letter of the output. Capitalizing the first letter of a string is a fundamental operation. So, surely, PyTon must provide a capitalized built in function to help us fix this issue. Hmm. It looks like the capitalized function does not exist. How strange? Well, the capitalized operation is, in fact, available in PyTN, but it is not implemented as a built in function. Instead, the capitalized operation is implemented as a built in type method. In this video, we'll show how to use built in type methods to perform common operations and clarify the distinctions between type methods and built in functions. Much like built in functions, type methods or tools that allow programmers to perform common tasks quickly. Yet there are subtle differences between the two notions, built in functions or versatile tools designed to operate on various data types. They provide programmers with a flexible toolkit. In contrast, built in type methods are specialized tools designed to work on a specific data type. They provide programmers with a type tailored toolkit. For example, capitalizing the first letter of a value makes sense if that value is a string, but it doesn't really make sense if that value is a number. For that reason, the capitalized operation is found under the umbrella of string methods instead of built in functions. Let's now see how to access the capitalized operation and use it on the label variable. To call a type method on a variable, we must follow the variable name with a dot. At that point, no pun intended. Most programming environments will present you with a list of available methods. That is a list of operations that can be performed on the variable. Let's scroll through the list and see if we can identify a good candidate for our purpose. Oh, would you look at that? A method called capitalize is available. That's promising. Et's select that method. Before we execute the cell, we must append a pair of empty parentheses at the end of the method's name. We'll say more about that in the exercise video. When we execute the cell, we can see that the method return or label string with the first letter capitalized. Note that applying the capitalized method to the label variable did not change the value of the label. Instead, it created a copy of the original variable with a capitalized first letter. To modify the content of the label variable, we must reassign the capitalized string. In line with our previous discussion, note that the capitalized method can only be applied to strings. For example, if we try to apply this method to the variable result, we get an error message. Other data types, such as integers and floats, also have their associated methods. We'll explore some of them in the exercises. Now, I'll admit that the difference between built in functions and type methods is somewhat subtle. To clarify the distinction, let's consider the following real life analogy. Imagine you're at the grocery store to pick up some coffee beans and oranges. Every item in the store, including oranges and coffee beans, can be added to your card and purchased at the checkout counter. In that sense, the operations of adding items to your card and checking out mirror the concept of built in functions in programming. They are generic operations that work on many types of items. However, once you're home, the way you prepare your food will depend on the items type. For example, you might want to grind your coffee beans and brew them in hot water, and you might want to peel your oranges and press them into juice. These actions are tailored to the specific items and therefore, resemble type methods in programming. Just as it doesn't make sense to try brewing oranges or peeling coffee beans, type methods are specialized operations that don't universally apply across different data types. Great. We now have a better understanding of built in type methods and how they are distinct from built in functions. In the next video, we'll explore a few additional built in type methods and see how they can help us manipulate data. 17. Built-in Type Methods - Guided Examples: Jimmy and Pike just completed their steep ascent. The two hikers continue on the trail at a good pace, but it's getting even warmer outside. Jamie is curious to know what the feels like temperature is. Using his sensors to measure the temperature, wind, and humidity, Pike calculates the feels like temperature. Pike has now learned that Jim would like some context around the output of his calculations. But because he is unsure of how Jimi wants the result formatted, he outputs the information with random capitalization. Oh, Pike. Unsatisfied with the format, Jamie asks Pike to show her a few options. The first option Pike proposes is to swap the case of all the characters in his output. In Python, this can be done using the swap case method. Unfortunately, the new format is just as hard to read as the original one. Pike gives it another try and converts all the characters to uppercase. In our code, we can do this using the method upper. Converting to all caps can be useful to emphasize important messages or to create case uniformity. But Jamie thinks it's a bit rude. Pike is not giving up. I tries again by converting all the characters to lowercase. In PyTon, the lower string method converts strings to lowercase. Like the upper method, the lowercase method can be used to create case uniformity. This output is clearly more readable, but it still lacks proper capitalization. Persistent Pike tries again and convert it output to title case. We can convert strings to title case as well, using the provided title string method. Title case can be useful when formatting a string for a heading or a title. This output is much more readable but isn't quite satisfying. Pike, you're so close. With one more trick up is robotic sleeve. Pike modifies it output formatting to be a normal sentence capitalization using the capitalize method. Great. Jamie is happy with the new formatting. No need to be fancy. Pike takes note of following this style in the future. Awesome. We have now seen several useful built in string methods in action. In the next video, you'll get the chance to practice using built in functions and built in type methods to operate on data. 18. Built-in Type Methods - Exercise Solutions: In this workbook, you saw how to use several more string methods. Let's discuss the solutions. To solve exercise one, we need to use the count method. If we call the count method on code one and pass the string ocean in as an argument, we can see that the word ocean occurs 14 times within the message. To solve exercise two, we can use the strip family of methods to remove the distraction characters. You can either apply the strip method repeatedly, or you can be a bit more precise and use the Strip and R strip methods where the distraction characters appear only on one side of the string. Let's focus on this more precise solution. First, we must strip the extra spaces from both ends of code two. We can use the strip method with no arguments to accomplish this. Second, we can remove the apostrophe characters from the front of the string by passing the apostrophe into the Strip method. Likewise, we can also remove the exclamation mark characters from the front of the string by passing in the exclamation mark as an argument to the Strip method. Then we can pass nine into the R Strip method to remove the nines from the end of the string. Finally, we can call R Strip with no arguments to remove the spaces at the end of the string. Great. We are then left with the string Apple Grove. Note that the order in which these methods are applied is important, since strip will only remove the characters at the beginning or the end of the string. It will not remove characters in any other location. Moving to exercise three, we need to use the replace method. Using method chaining, we can replace the zeros and ones in code three with the empty string. Then we can replace the twos with D, the threes with B, the fours with L, the fives with A, the sixes with M, the sevens with R, the eights with Y, and the nines with I. This allows us to decode the message to get the word library. Then to solve exercise four, we can use the find method with the string library as an argument to find the location in code one where the word library starts. We obtain that library starts at character 1,114. Finally, in Exercise five, we introduced the concept of Booleans as values that can be either true or false. Strings and numeric values have methods that return booleans. These methods allow us to ask questions about our data. For example, we can determine if code four is alphanumeric by calling the I lnum method. Here, we find that the code is indeed alphanumeric. Awesome. Over the last two workbooks, you have learned how to identify functions and methods that you can use to solve a given problem. This is a useful skill that you will draw upon going forward in your programming journey. In the next few videos, we will dive into the Boolean type that we saw in Exercise five and learn how this type opens up a new class of problems for us to solve. 19. Booleans and Comparison Operators: In the previous exercise workbook, we use the method is digit. We noticed that this method returned the value true, which is of the Boolean datatype in this video. We'll explore this new data type in greater details. Booleans are a datatype that can only take the values true or false. At first glance, a datatype that can only take one of two values may seem of limited use. But it is, in fact, this very limitation that makes booleans so powerful. Let's see why. By analogy, Booleans mirror the possible states of a light switch, either on, true or off, false. In practice, Booleans are useful when we want PyTon to answer yes or no questions. For instance, imagine you have difficulty with numbers and require PyTn's assistance to determine if 40 degrees Fahrenheit is above the freezing point, which is 32 degrees. We can ask PyTon this question using a comparison expression. Comparison expression tests whether two values satisfy a certain relationship and returns the value true if the relationship is satisfied and false if it is not. For instance, to determine if 40 degrees is above freezing, we can use the greater than comparison operator. When PyTon evaluates the statement, it returns the Boolean value true, indicating that 40 is indeed greater than 32. You are learning a lot today. Conversely, if we use the less than operator in the statement, PyTN evaluates it to false. We can similarly test weak inequality relationships using the greater or equal operator and the less than or equal operator. Beyond numerical values, Python comparison expressions can also be used to compare strings and other data types. For example, let's assign the string Tuesday to the variable day one, and the string Monday to the variable day two. Now, let's say we want to test whether these two strings are the same. Can we use the equal sign as a comparison operator? Of course not. Remember, the equal sign is the assignment operator in Pyton. Evaluating this expression reassigns the string Monday to the variable day one, which wasn't our original intention. To create an equality comparison expression, we must instead use the double equal operator. Since the strings Monday and Tuesday differ, evaluating the expression returns the value false. Finally, if we instead want to test if two values are different, we use the inequality operator exclamation point equal. Replacing the first equal sign with an exclamation mark and evaluating the expression, we obtain the value true, indicating that the two strings are indeed different. Great. We have covered yet another PyTN data type, Booleans. In particular, we have seen that Booleans are very useful to ask yes or no questions within the PTN program. In the next video, we will build upon this foundation and see how we can ask more complex questions in PTN. 20. Booleans and Comparison Operators - Guided Examples: Trekking along the roller coaster trail, Jamie and Pike have just hit the two mile mark. Full of energy, Jamie wonders whether they can pick up the pace. To do so, Pike would need at least 73% of his battery left to boost up to turbo speed. Jamie, on her side, would feel comfortable hiking faster, knowing that a few clouds are in the forecast to block out the intense sun. In essence, Jamie and Pike want to answer the following yes or no questions. Is Pike's battery level greater than 73%? And is the weather forecast cloudy? They can't hike faster unless the answer to both questions is yes. Let's see how we can ask PTN whether these two conditions are simultaneously satisfied. Conveniently, PTN provides the keyword to help us perform that test. The end logical operator, when placed between two boolean values, allows us to check if the two values are simultaneously true. If the two values are true, the entire logical expression evaluates to true. On the other hand, if at least one of the value is false, the logical expression evaluates to false. Pike calculates that he has 65% battery remaining and predicts that some clouds will show up during the remainder of the hike. Let's use that information to figure out if going faster is an option. We'll begin by creating two variables to represent Pike's battery level and weather forecast. Then we can ask whether Pike's battery level is at least 73% and whether the weather forecast is cloudy as follows. Executing the cell, we obtain false. Of course we do. The first Bolling expression is clearly false. That's a bummer. Jamie and Pike will not be able to hike any faster. But wait. Jamie has another idea. When they venture out in the wilderness, Pike usually brings some backup power. Jamie asks Pike if he brought either a portable battery or his mini Winterbine. Having either the battery or the win turbine would be sufficient to give Pike some more charge. In this situation, Jamie wants to answer the question. Did Pike bring either the portable battery or the mini win turbine? To ask questions like this, Biton provides another logical operator, the operator or when placed between two booleans, the or operator verifies if either value is true. If at least one of the values is true, the entire logical expression evaluates to true. Only when both boolean values are false, does the logical expression evaluates to false. Pike scans his internal inventory and informs Jamie that he brought his mini wind turbine, but not a portable battery. We can use this information to set up another logical expression. Let's first create two boolean variables to indicate that Pike brought the mini turbine, but not the portable battery. Then we can perform the test by simply writing has mini turbine or has portable battery. Note that there is no need for comparison expressions here because our two variables are already booleans. Executing the cell, our logical expression evaluates to true. Again, this is what we expected because at least one of our two variables is true. Awesome. Pike can now attach the turbine to harness the power of the wind and charges battery a few extra percent. Then Jamie and Pike will be able to continue their hike at an even faster pace. Great. You now know how to use comparison and logical operators to ask yes or no questions within the PTN program. It's now time to practice this new skill. 21. Booleans and Comparison Operators - Exercise Solutions: In this workbook, you got some more experience with the Boolean type and comparison and logical operators. Let's go through the exercises. In exercise one, you built some more complex comparison statements. To solve part A, we need to calculate the average temperatures early in the week and late in the week. We can store those values in variables and then use the greater than operator to test whether it is the case that the early temperatures were greater than the later temperatures. The comparison results in false, which means the average temperature earlier in the week is less than the average temperature later in the week. In Part B, we need to determine if the absolute temperature change between Monday and Tuesday is at least as large as the absolute temperature change between Thursday and Friday. We can use the ABS function to calculate the absolute differences. Then we can use the greater than or equal operator to identify whether the absolute difference between Monday and Tuesday is at least as large as the absolute difference between Thursday and Friday. We find that the comparison results in true, which means the temperature changed more between Monday and Tuesday than it did between Thursday and Friday. Moving to exercise two, we can check whether the temperature is strictly increasing from Monday to Thursday using multiple less than operators. This statement is asking three questions in one. It asks whether Monday's temperature is less than Tuesdays, whether Tuesday's temperature is less than Wednesdays and whether Wednesday's temperature is less than Thursdays. Our statement evaluates to true, indicating that these four temperature values are strictly increasing. In exercise three, we introduced the knot operator. We can use the operator to solve this problem in two different ways. First, the more intuitive approach is to directly negate both the will rain and temperature will drop variables. However, it is logically equivalent to check if will rain or temp will drop are true and then negate the group. This works because of De Morgan's law, which says that not A and not B is the same as not A or B. In both expressions, temp greater than or equal to 90 will evalue it to true. Then in the first expression, both not will reign and not temp will drop, evalue it to true. Three trues linked with and operators results in true. In the second expression, will reign and temp will drop are false, and they are linked with an or operator. So this expression will evalue it to false. But we apply then operator, which turns the false into a true. Then we are evaluating true and true, which is true. Next, in exercise four. When tackling complex comparison and logical expressions, it is best to break them down into smaller parts. We can do that here by first accounting for the fact that it should not be hailing. Then we see the word and so we know the remainder of the expression will be joined with an and keyword. Also, because of the phrase, one of the following conditions must be true, we know that these two conditions will be joined with an or operator. Next, we can translate at least 500 yards of visibility and a precipitation rate of no more than 0.2 "/hour into this statement. And we can translate no less than 600 yards of visibility and a precipitation rate of no more than 0.3 "/hour into this statement. Given our input variables, this part of the expression evaluates to true. This part of the expression evaluates to false, and this part also evaluates to false. These two expressions are linked with an or, so false or false is false. As a result, we are left with true and false, which is false. Finally, moving to exercise five. In part A, we create four variables and set them equal to placeholder values. Then in Part B, we use these variables to set up an expression to determine whether there is an increased avalanche risk. Because we need to know if one of these conditions is true, we will use an or operator to link them. We can check if there has been more than 12 " of recent snowfall and if there are three or more weak layers. And we can also check if the wind speed is greater than 20 miles per hour, and there has been a large temperature change. Finally, in Part C, we can replace the placeholder values of our variables and evaluate the expression to get that there is not an increased risk of avalanches. Great. Now that you have practiced creating comparison and logical expressions, we are ready to move on to our next topic, conditionals. Booleans and logical expressions are an important part of conditionals, so you will have the opportunity to practice them even more in the future. 22. Conditionals: In the previous videos, we explored how to answer yes or no questions and PTN using comparison and logical expressions. In this video, we will study how to use these expressions to control the execution flow of our code. All of the PTN programs we have written so far run linearly, moving from one line to the very next until the end of the program. By analogy, the execution of our code has been like a smooth drive on a straight highway leading directly to our destination. But in programming, as in driving, the path we want to follow isn't always straightforward. Just as you might need to detour to a rest area if your car is low on gas, programmers often need to control the execution flow of their code based on certain conditions. For example, suppose you are designing a simple driving assistant program that alerts drivers when it's time to fuel. The program must work as follows. If a car passes by a rest area when it has less than one fourth of a tank, the program must output the string time to fuel, baby. In programming, conditional execution decisions like that can be implemented with I statements. And if statement begins with the keyword, I followed by the condition we want to test and a column. Note that when pressing Enter after writing the terminal column, the next line of code becomes automatically indented. This is not a glitch. The indentation signals to Python that the code we write on this line must be executed only if the comparison expression is true. If the comparison expression is false, the indented line of code will be skipped at execution. We can easily verify that our program performs as intended. If we assign the value 0.1 to the variable gas remaining and execute the code, the desired string is printed. And if we assign the value 0.5, nothing appears in the output box. Now, a program that returns nothing is a bit unsettling. It makes it hard to tell whether or not the program has been executed. Let's improve our code by having the program output the string continue straight at the very end. This string should be printed whether or not the comparison expression is true. This can be done in PyTon by writing an unindented print statement under the current line. Testing our code with the value 0.1, we observe that both print statements are executed. And changing 0.1 to 0.5, only the final print statement gets executed. As you can see, proper indentation is key when working with if statements because it determines the scope of the statement. If statements are powerful, but they are just one building block that Python provides us to control the flow of our code. Piton also provides more building blocks to handle more complex scenarios. For example, imagine you are approaching a T intersection and must decide based on the amount of gas remaining whether to take the short path or the scenic route. If you have more than half a tank, you can take the scenic route. If not, you must take the shorter path, otherwise, you would run out of gas. This scenario differs from the previous one because here we must choose between left or right. We can't skip this choice altogether and continue straight. To help drivers make such a decision, let's create a second version of a driver assistance program. This new version will still execute a specific piece of code when the condition is true. But then if this condition is false, we want our code to execute a different piece of code. To achieve that, we write the Ls keyword followed by a column on the same indentation level as the I statement. Under the statement, we write on an indented line of code, the piece of code that we want executed if the condition is false. Finally, for the sake of completeness, let's write an unindented line of code that will be executed regardless of the chosen path. Let's now test if our code work as expected. If we set the variable gas remaining to 0.7, the code associated with the I statement is executed. And if we change the variable gas remaining to a value of 0.3, the code associated with the Ls statement is executed. Note that in both scenarios, the final print statement is always executed since it is outside of the scope of the conditional block. I and IL statements are powerful concepts that enable programmers to control the execution flow of their code. In particular, the IL structure is very helpful for situations that involve two mutually exclusive scenarios in the next video, we will generalize this IL structure to accommodate situations where there are two, three, four, or even more possible scenarios. 23. Conditionals - Guided Examples: As Jamie and Pike approach the summit, they reach a critical junction where they must choose one of three paths. The appropriate path to follow depends on Jamie's energy level, which can either be high, medium or low. If Jamie has high energy, they will be right extending their journey by an additional 2.8 miles. If our energy is medium, they will continue straight, maintaining the original high cland of 4.73 miles. Finally, if our energy is low, they will take a shortcut by veering left, reducing the track by 0.56 mile. Let's use conditional statements to represent the decision process. We'll build upon concepts we are already familiar with. In the last video, we learn how to direct or code down two paths based on the value of a logical expression using I and's statements. Well, it turns out that we can extend this approach to guide the execution of our code down three or even more paths. For example, we can implement the following logic to decide which path Jamie must take. First, we test whether Jamie's energy level is high with an I statement. If this condition is true, Jamie will take the path that adds 2.8 miles to her hike. But if this condition is false, we must determine whether her energy level is medium or low. This can be done by embedding another Is block in the first s block to test if our energy level is medium. If the condition is true, Jamie will follow the route originally planned. But if this condition is false, we can infer that Jamie's energy level is low and she should take the shortcut. As this example illustrates, we can represent multiple choices by nesting if else blocks. While this approach works reasonably well for three alternatives, it quickly becomes burdensome when there are more possibilities. You'll get to experience just how conversome it becomes in the exercises. Thankfully, there's a better way. To simplify programmers lives, PyTon provides the keyword LIF, which stands for s if. The code in the ALIF block is executed if and only if the expression of the if statement is false, and the expression of the ALF statement is true. In practice, ALIF statements can be used to implement the same logic as nested ifelse blocks, but they are much easier to read. By following the logic, Pie can determine which path to follow. Let's implement that logic in Python. First, we'll test if JB's energy level is high with an if statement. If that's the case, we first update the hiking distance accordingly. And output the path to follow. Note that conditional statements may include multiple lines of code. Indentation determines whether a line of code is part of the statement. We follow the I statement with an IF statement to test if Jamie's energy level is medium. Since we do not need to update the hiking distance, in that case, there is no need to reassign the variable total miles. We complete our conditional block with an L statement to handle the case in which Jamie's energy level is low. In that case, we must decrease the value of total miles by 0.56. Finally, let's write an unindented print statement to output the updated total miles. Because this last line of code is not part of the If conditional block, it will be executed every time we run the program. Upon Pike's inquiry, Jamie concedes having a medium energy level. Let's assign the variable energy level accordingly. Then executing the cell, our program recommends sticking to the original plan. Awesome. Jamie and Pike will then continue on their original path up to the summit. We'll leave Jamie and Pike complete this hike and catch up with them once they return home. Awesome. We now understand how to use conditional statements to control the execution flow of our code. In the next workbook, you'll have the chance to practice using conditional statements. 24. Conditionals - Exercise Solutions: In this workbook, you practice using conditionals in several different circumstances. Let's discuss the solutions. In exercise one, you experienced how the F block can make your code easier to read. In Part A, we can nest if and else Block to update the hours to explore variable based on the environment condition. While these two code blocks are logically equivalent, it is best practice to explicitly test for all of our conditions. Leaving the success state to be handled by the else block can cause unexpected behavior if your program receives erroneous inputs. In Part B, we can use the LF keyword instead of nesting if else blocks. This makes our code cleaner while being logically equivalent. In exercise two, you saw two scenarios in which nesting conditional blocks might be the better option. In part A, we want to nest conditionals because each check is a prerequisite for the next check. First, we ask whether the field check passes. If it does, then we can check if the crew check passes. If it does, then we can do our final navigation check. If that check passes, then we print the launch ready message. If any of those checks fail, we print a specific error message to indicate exactly which check failed. Moving to Part B, we encounter another situation in which nesting conditionals is the best option. Here, we want to nest conditionals because we need to verify that the Zeus rocket is both available and operational before we continue checking the other conditions. We can check those other conditions using a nested I LFL block where each condition checks whether the mission type matches the crew available and fails if there is no match. To solve exercise three, we need to be mindful of the order in which we check our conditions. We need to first check whether the engine temperature is greater than 90 so that we can output the correct message. If instead, we first check whether the engine temperature is greater than 50, all temperatures that meet that condition, including temperatures that meet other conditions will incorrectly cause the caution message to be printed. As you can see, you need to be mindful of the order in which you check your conditions to ensure that your code behaves as expected. Finally, in exercise four, we can utilize the ternary operator to write a conditional on a single line. We would like the status to be sufficient if food supply is greater than 50. Otherwise, it should be insufficient. Awesome. You now have a solid understanding of conditionals and conditional logic. In the next few videos, we will shift to exploring another useful data type, lists. 25. Lists: In the previous video, we saw how to use strings to represent data. In particular, we consider the example of a shepherd spy ingredients that we represented in one long string. While this method works, it's not the most efficient way to access and manipulate each ingredient. In this video, we'll explore a better way to organize this type of information using PyTon lists. Lists are versatile tools that can store collections of items such as the ingredients in a recipe. Lists allow us to maintain order, access items easily, and perform many operations such as adding and removing items. For example, we can represent the Shepherds By ingredients as a list of strings. To create a list in Piton, we enclose its item within square brackets and separate each item with a comma. Just like each character in a string has an associated index. Each item in a list is also associated with an index. For example, to retrieve veggie brat from our list, we put brackets at the end of the ingredients variable and include the corresponding index for inside them. Now that you understand the basics, let's make a few more observations. First, lists in Piton can store anywhere from a few items to several million of them. That is to say that lists can be used to represent a few grocery items or to represent the inventory of an entire grocery store. Second, lists are incredibly versatile. They can hold strings, integers, floats, booleans, or a combination of these. We can even create lists that contain other lists. In our upcoming videos, we'll explore these possibilities further. Moreover, we'll dig in some of the built in methods available for lists. As we explore these methods, you'll see firsthand why lists are better than strings to organize collections of related items. 26. Lists - Guided Examples: Jimmy and Pike are back home after their exhilating adventure on the roller coaster trail. Eager to embark on another journey, Pike suggests planning a more ambitious hike that involves navigating between multiple waypoints. Jimmy agrees, but notes that this will require careful preparation. The first step in their planning process is to compile a list of waypoints. Pike proposes an adventurous route starting from Eagles Crest Trailhead, leading to Crystal Brook Bend, descending into Echo Canyon, climbing out of misty falls and culminating with a steep climb at Mount Silvercrest. Let's represent this list of waypoints in Biton. Between square brackets, we write strings to represent each of the five waypoints and separate those strings with amas. Then we assign our newly created list to the variable waypoints. To verify that our list was created properly, let's visualize it. Great. According to Pike, everything looks good, but that's when Janie realizes that they forgot to specify their route to get back home. Oops. Pikes suggest they pass by Star Watch lookout, continue their trek toward Jem Lake, and then return to Eagles Crest Trailhead. To add these waypoints to the list, PyTon provides us with the method append, which takes the item to append as an argument. Let's verify that the waypoints have indeed been added. Wonderful. As you might have anticipated, the items were appended to the end of the list in the order in which they were added. While him agrees with Pike's suggestions, she also suggests they stop at Pipers Cove for the scenic views before hiking to Jem lake. To add an item at a specific position in a list, Piton provides us with the insert method. This method takes two arguments. The first argument specifies the index where the value must be inserted. The second argument specifies the value to be inserted. When we execute the cell, we obtain an updated list where Piper's Cove has been inserted before Gem lake. Seeing the full list of destinations, Jamie feels they are being overly ambitious. Consequently, Pike proposes removing Crystal Brook Band from their itinerary since it's too far from the other waypoints. To remove an item from the list, PyTon provides us with the remove method. This method takes the item to be removed as an argument. Oh, no. What happened? Why do we get an error message here? Well, notice that we did not capitalize Crystal Brook Ben in the same way as it appears in the list. We have essentially tried to remove an item that doesn't exist in the list, and PyTon didn't like that. Correcting the capitalization, we remove the item successfully. Perfect. Jamie and Pike are now both satisfied with the list. Curious, Jamie asks Pike how many waypoints they will visit during their hike. To determine the number of elements in the list, we can use a function we are already familiar with the LN function. Eight waypoints to visit. This hike is going to be lots of fun. Awesome. Now that we have seen several useful built in methods for lists, it is time for you to practice. In the next video, you'll have the chance to work on some exercises on these concepts. 27. Lists - Exercise Solutions: In this workbook, you got to practice using lists to store, organize and operate on data. Let's break down the solutions. To solve exercise one, we can use the syntax and methods that we saw in the previous videos. In Part A, we create the packing list by enclosing our data between square brackets. In Part B, we can use the append method to add toothbrush and phone charger to our packing list. Then in Part C, to insert book after sunglasses, we use the insert method. We pass in three, which tells Python to insert our data at the third index, and we pass in book as the data we would like to insert. Finally, for exercise one, Part D, we can remove sunglasses by passing it in as an argument to the remove method. Moving to exercise two, Part A, we can sort our packing list in alphabetical order using the sorted built in function. Python also provides the list method sort, which sorts elements of a list in alphabetical order. Both the sorted function and the SRT method, technically sort lists in ascending order. For string data, like we have here, this means alphabetically. For numeric data, this just means from lowest to highest value. Also note that the sorted function does not modify the original list, but the sort method does. Then in Part B, we can sort our packing list in reverse alphabetical order by first applying the sort method and then the reverse method. But this is not the only way to reverse alphabetize a list. We can also apply the sort method with the reverse equals true argument. Or we can call the sorted function and pass its result directly into the reverse function. Just be aware that if you do not cast this result to a list, you will end up with this unhelpful output. Casting our result to a list, we now have our reverse alphabetize packing list. In exercise three, we introduced the concept of multidimensional lists. This can be a tricky concept to wrap your head around, so don't be discouraged if these exercises seemed a bit more difficult. In Part A, we can create a multidimensional list to store the expenses for each city like this. The zeroth index of each sub list stores the city, and the first index stores the list of expenses. The zero value in this list is the expected accommodations expense. The first value is the expected food expense, and the second value is the expected transport expense. In Part B, we can assign the correct values to each variable as follows. To access London England from our expenses list, we specify zero for the zeroth sub list, and then zero again for the zeroth element in that list. This same logic applies for the other city strings. Then to access the accommodations expense for Paris, we can specify one to get this list, one again to get this list, and then zero to retrieve the zeroth element. For the Paris food and travel expenses, we simply modify the third index to retrieve the correct value. Next, to access the accommodations expense for London, we specify the indexes zero, one, and zero. To access the food expense for Venice, we specify 31 and one. And for the Munich travel expense, we specify 21 and two. In Part C, we can utilize the sum, Min and MX functions to answer our three questions. We pass the first index in the zeroth list into the sum function, which then returns the sum of the list items. Then to find the least amount we expect to spend on food, we can use the Min function. We pass in the first index of the first element in each of the city lists, and the Min function finds the smallest one. To answer the third question, we can pass the expenses list for Venice into the MAX function. Moving to exercise four, Part A, we can create three lists, destinations, distances, and times using the normal List syntax. In Part B, we use the zip function and cast our result to a list to group the data at each index together. Our result is a list of tuples where all the data relating to Paris is at the zeroth index. The data relating to Munich is at the first index, and the data relating to Venice is at the second index. Great. Now you have gotten to practice using and operating on lists, and you got to learn a few new concepts related to lists, which make them even more useful. In the next video, we will dive into tuples and learn how they are distinct from 28. Tuples: In the previous exercise workbook, we use the zip function to combine related elements from three different lists into a single list. We noticed that the element of that single list are so called tuples. Hm. In this video, we study these tuples in greater detail and explore how they are similar, yet different from lists. Similar to lists, tuples are collections of items. But to create a tuple, we enclose the items of a collection within parentheses instead of square brackets. Like lists, tuples also support indexing. Individual items and slices of items can be accessed using standard syntax. The differences between tuples and lists become apparent when we start using them. As we demonstrated in previous videos, once a list is created, it can be modified with methods such as append, insert and remove. In contrast to lists, tuples cannot be modified once they are created. Accordingly, there are no append, insert or remove methods associated with tuples. Moreover, the few methods available do not perform modifications on tuples. In other words, the big difference between lists and tuples is that lists are modifiable after creation, and topples are not. Being unable to modify a collection is a significant limitation. So why would someone ever want to use a tuple instead of a more flexible list? Well, precisely because tuples are unmodifiable. They are a valuable tool for organizing data that needs to stay consistent throughout a program. For example, the road trip stop tuple that we defined earlier contains information that is definitive. The distance between London and Paris is set in stone and should not be changed. Any modification to this value would be a mistake. As another example, geographic coordinates are also a type of data that we may want to store in a tupple. The latitude and longitude of New York City will never change. Using a tuple guarantees that we won't accidentally modify those values at some point in a program. Great. We now understand what topples are and how they differ from list. Although topples are less frequently used than list, they are ideal for storing information that must remain unchanged. In the next video, we'll explore another valuable yet less common data type to store collections, sets. 29. Sets: In the last few videos, we saw how to represent collections of items using lists and tuples. In this video, we introduce a third and final data type used to represent collections of items, sets. Sets are used less frequently than lists. Nonetheless, we will see that there are a few situations where sets are preferable. Sets, like lists and tuples are collections of items. In Python, we create a set by enumerating its item in between curly brackets. Beyond this difference in syntax, there are two main distinctions between sets and the other types of collections. First, while lists and tuples may contain duplicate items, the items of a set are unique. For example, we may represent the single banana, three oranges, and two apples that compose a fruit bowl using a list. But if we instead represent the same collection of fruits using a set, the duplicate items are removed, and we are left with a collection of three distinct fruits. This property of sets is helpful in practice when we want to obtain the unique values of an existing list. For example, suppose we have this list containing duplicate values. We can quickly obtain the unique values of the list by casting it to a set using the set casting function. The second big difference between sets and the other types of collections is that a set does not assign a specific position to its items. In other words, the items in sets are not associated with an index value specifying their position in the collection. In programming, when the items of a collection are assigned a specific position, we say that the collection is ordered. On the other hand, when the items of a collection have no specific positions, we say that the collection is unordered. Finally, there is an additional distinction between sets and tuples. Like lists, sets are modifiable. To illustrate, let's know that we can add a new item to a set using the add method. As you can see, apricot has been added to the set. Note that the existing items have changed positions, consistent with the observation that sets are not ordered. Sets are great for representing data when the existence of an item is more significant than its position. Awesome. We have now seen three distinct data types to represent collections of items. Each type has strands and limitations that make it more or less suitable depending on the use case. Lists are the most popular tool to represent collections. They are modifiable after creation, allow duplicates and are ordered. Tuples and sets are less common, but they are useful in specific situations. Tuples are not modifiable, allow duplicates and are ordered. They are great for storing data that should not change during a program. Finally, sets are modifiable, but do not allow duplicates and are not ordered. This means that sets are most useful when we want to ensure that our collection contains unique items. In the next video, we will explore a few scenarios where tuples and sets are preferable to list. I'll see you there. 30. Collections - Guided Examples: At the trailhead of Eagles Crest, Jamie takes a deep breath of the crisp, fresh air and embarks on her hike. Excited to immerse herself in nature, Jamie proposes to keep an inventory of all the wildlife they encounter. Always eager to assist Pike volunteers to document their findings. Shortly after departing from Eagles Crest Trailhead, Jamie and Pike's journey gets exciting as they spot two deers and a rabbit froliing nearby. As they meander between Echo Canyon and Misty falls, Jamie notices another deer and a majestic elk amidst the dense foliage. On their way to Mount Silvercrest Summit, Pike spots a pair of mountain goats skillfully navigating the rocky cliffs and three more elk grazing in the distance. Approaching Star Watch Lookout, they witness a bear lumbering along the far side of the riverbank. Finally, as they head back to Eagles crest Trailhead to wrap up their hike, Jamie excitedly points out a pair of moose by the water's edge. They perfect finally to their wildlife rich expedition. Awesome. We'll now use Python to document the collection of wildlife sightings. Out of the three types of collections we are familiar with, which do you think is best to represent that type of information? As you can see, this collection contains duplicate values because Jamie and Pike recorded multiple sightings of the same species. As a result, if we were to represent the collection using a set, we would lose some information as the duplicate values would be eliminated. Moreover, because Jamie and Pike have already completed their hike, we know that they will not add more animals to this collection. The collection is set in stone. For those reasons, using a tupple seems appropriate here. Remember, the difference between lists and tupples is that tuples cannot be modified after creation. Once they have returned home, Jamie asks Pike to report the unique species they encountered on the trail. To obtain this information, we can cast the wildlife tuple into a set. Doing so transforms a copy of the wildlife tuple into a set removing the duplicate values. Pike informs Jamie that they have encountered bears, deer, elk, moose, mountain goats, and rabbits. That's great. Jamie is thrilled to have seen so many species of wildlife. She wonders how many more animals they could potentially have seen. Specifically, Jamie wants to know which of the animals that live in our area they have not encountered during the hike. To help Jamie, Bike consults an old local wildlife guide and finds the collection of all animals inhabiting the area. Let's represent that collection of animals using a set. Great. Now, to answer Jamie's question, we must determine which animals are in the possible wildlife set, but not in the wildlife set. In PyTon, this can be done by calling the difference method on the possible wildlife set and passing the variable wildlife as an argument. As the name suggests, the difference method returns a set containing elements that are in the calling set, but not in the set passed as an argument. Executing the cell reveals a set containing three animals that Jamie and Pike did not see but could have seen. When Pike informs Jamie that they could have seen bighorn sheep, bison, and eagles, Jamie indeed recalls seeing some of these animals on their first hike in the area several months ago. She asks Pike to help her remember exactly which of these three animals she has seen on their first hike. Thankfully, Pike is a reliable record keeper and save that collection on his hard drive. Assigning the wildlife scene on the first hike into a set, we can use another method to determine which items occur in both sets. To do that in PTN, we can call the intersection set method on the first wildlife set and pass in the not seen wildlife set as an argument. The intersection method returns a set containing the elements that are in the calling set, and in the set passed as an argument. Executing the cell, we obtain bighorn sheep and Bison. This means that Jamie and Pike saw bighorn sheep and Bison on their first hike, but not on their second hike. Great. Over the last several videos, we have seen when to use lists, touples and sets depending on our programming needs. In the following exercises, you'll get to practice how to use all three of these data types. 31. Collections - Exercise Solutions: In this workbook, you had the opportunity to practice choosing the correct collection type for a given context. Additionally, you used each type specific operations to solve problems. Let's discuss the solutions. In Exercise one, Part A, we are tasked with choosing a data type to store the new book information. We know this information will not change in the future, and that the order in which the information is presented is significant. Therefore, we should represent the new book information with a tuple. In Part B, we were introduced to the concept of unpacking. We can unpack our new book tuple into three variables, title, author, and year, like this. Moving to exercise two, P A, we now need to represent the genres of the checked out books. See that this collection of genres contains duplicate values, which rules out using sets. We also know that this data will be updated in the future when books are checked out or checked back in, which rules out using tuples. So in this scenario, it is best to use a list. In Part B, two science fiction books and a mystery book were just returned, and three biographies, two poetry books, and a fantasy book were just checked out. We can update the checked out genres list accordingly, using the remove and append methods. Then in Part C, we can count the number of fantasy and poetry books that are checked out using the count method. We obtain that there are two fantasy books and two poetry books that are currently checked out. Finally, in exercise three, P A, the librarian would like a collection of the unique genres that are currently checked out. Because we are looking for the unique genres, we need to use a set. We can create a set from the checked out genres list from exercise two with a set casting function. In Part B, we use curly brackets to create a set with the genres of books that are not checked out. Then in Part C, we can use set operations to ask questions about the checked out genres and available genre sets. First, we can use the union set method to get all of the genres across the two sets and use the n function to count 11 total genres. Second, we can determine which genres are both checked out and available with the intersection set method. Remember, the intersection of two sets are the elements that occur in both sets. We obtain that the biography, fantasy and poetry genres are both checked out and still available. Third, we can find which genres are available but not checked out with the difference method. Because we wish to find the genres that are in the available genre set, but not the checked out genre set, we must call the difference method on the available genre set and pass in the checked out genres as an argument. If we call the difference method on checked out genres and pass in available genres as an argument instead, we will get those genres which are checked out but not available, which is the opposite of what we want. Finally, for question four, we use the symmetric difference set method to find those genres that occur in one set or the other, but not both. We then apply the n function to count that there are eight genres that are either checked out or available. Great. Now that you understand collections, we are ready to tackle one of the more difficult topics in this course, loops. Loops are very useful for working with collections because they allow us to efficiently apply operations to every element of a collection. In the next few videos, we will break down loops into an approachable concept and then learn how to use them in more complex situations. 32. For Loops: In the previous video, we discussed how to represent collections of items using lists, tuples, and sets. Moreover, we highlighted the benefit of using collections when storing large amounts of data and studied how PyTn's powerful built in methods can help us manage those collections. But as we're about to see, managing large collections of items can sometimes be quite challenging. For example, suppose you're the owner of a store who wants to discount all inventory items by 30%. To accomplish this task, we can start by creating an empty list of discounted prices. Then we may utilize indexing to access each price, multiply it by 0.7, and append the result to the discounted price list. But as you can imagine, this will be quite tedious since there are many prices. Fortunately, there's a better way. In this video, we will learn how to automate repetitive tasks like discounting prices using a programming concept called four loops. By the end of this video, you'll see how loops can simplify and optimize your code. Let's dive in and see how it's done. For loops are structures that allow programmers to execute lines of code for each item in a collection. The four loop syntax in PyTon is very intuitive. To appreciate the simplicity of the syntax, we'll write a simple for loop that discount the prices in the prices list. Specifically, we'll do the following. For each price in the price list, let's apply a 30% discount and append the result to the discounted price list. Notice how close the Python syntax is to the English description of what we want to do. Let's complete our program with a print statement and execute the cell to confirm that the loop did indeed apply the discount to each item. Great. It does look like the discounted price list contains the discounts we were hoping for. If you have the patience, feel free to verify. Also note that it took only two lines of code to achieve the desired output. That's quite neat. Okay, now that we know the syntax, let's examine the anatomy of the loop a little bit more carefully. A four loop has two main components, a header that ends with a column and an indented body. This structure should look familiar at this point. Conditional statements, which we covered in the previous lectures, also follow a similar format. Let's take a closer look at the header of our four loop. First, the keyword four instructs Piton that the program is entering a block of code that might need to be repeated. The second component of the header is called an iteration variable or loop variable. This variable is used throughout the loop iterations to store the items of the list. We'll say more about that iteration variable shortly. For now, let's simply note that instead of price, we could use a different variable name such as two, two without any impact on our program's output. But while we are free to choose any name for the iteration variable, it is better to choose a representative variable name. In this example, price is a better name than 22, since it better evokes the nature of the items in the list. Next, the keyword in is used to introduce the collection over which to iterate. In this example, we are iterating over a collection called prices. The length of this collection determines the number of iterations the loop will perform. In this specific case, the prices list contains 30 prices. Therefore, Piton will execute the body of the four loop 30 times, once for each element in the prices list. Finally, the body of a four loop contains the code that PyTon will execute during each iteration. In this example, the body of the four loop, discount the price of an item and append the result to the discounted price list. Awesome. Now that we have examined closely the anatomy of our loop, let's study step by step how PyTon executes that loop. When during the program's execution, PTN reaches the loop's header for the first time, it creates the iteration variable price and assigns it the first item of the prices list. Then Pyton executes the code in the body of the loop. In this case, the body of the loop contains a single line of code, but there could be more. Since the iteration variable price takes the value 51.79 during the first iteration, the value 36.25 is appended to the discounted prices list. Following the execution of the code in the body of the loop, PyTon returns to the header. At that point, the iteration variable is reassigned the second item in the prices list. Then PyTon executes the code in the body of the loop again. Since the iteration variable takes the value 39.37 during the second iteration, the value 27.56 is appended to the discounted price list. Piton then returns to the header, reassigns the iteration variable, and executes the code in the body of the loop once again. This process continues until the iteration variable has been assigned every price in the prices list. When PyTon runs out of item, the loop execution is complete. PyTon then moves on to executing the remaining lines in the program. And this is generally how four loops are executed. One iteration at a time, starting from the first element of the collection and ending at the last one. Along the way, the iteration variable is sequentially reassigned to the next item of the collection. When performing repetitive tasks, loops have the advantage of being concise. These two lines of code are indeed doing a lot of heavy lifting for us. A related advantage of four loops is scalability. To illustrate this point, let's suppose that the store manager in our example discovers a few more items to discount and includes their prices in the list. With a four loop, our code accommodates this change without any modification. PTN automatically handles the change for us by performing a few more loop iterations. Without a loop, we would need to manually track the items that have been added and write more lines of code to apply the discount. Great. You now have a basic understanding of four loops and of why they are sometimes preferable to applying manually operations to the items of a list. In the next video, we will delve into a more complex use case for four loops. 33. For Loops - Guided Examples: Since the last few hikes went so well, Jamie decided to plan a more ambitious two day expedition for the upcoming weekend. Pike likes the idea and recommends a list of waypoints that culminate at the summit of Pine Ridge Mountain, where they can camp overnight. Let's represent the waypoints leading to Pine Ridge Mountain with a PyTon list. Because this hike will be more complicated than any previous ones, Jamie would like a list of tasks they should do at each waypoint to keep their trek safe and enjoyable. Pike suggests that at each waypoint, Jamie should drink water, eat a snack, take inventory of our supplies, and snap pictures to document their adventure. Always an eager note taker, Pike prepares a list of those tasks. Let's also represent this list in Python. Awesome. Now, let's sum up Jamie and Pike's game plan for their next expedition. From the Trailhead, the two will hike towards Granite Falls crossing. When they reach the crossing, Jimi will drink water, eat a snack, inventory supplies, and snap pictures. From there, they will head to Starlight Meadow. Upon arrival, they will again go through the list of tasks. Returning to the trail, they'll start hiking towards Cedar Creek Junction. Once they arrive, they will once again, complete the list of tasks. They'll then head out to Evergreen Grove, where you guessed it, Jamie and Pike will complete the tasks. Finally, after the last stretch of their hike, the pair will arrive at Pine Ridge Summit, where they will, one last time, complete the list of tasks. Wow. That was a lot of repetition. Can we print this to do list in PTon without having to explicitly type out every activity at each waypoint? Because that seems kind of tedious to me. Well, when some programming tasks need to be performed repeatedly, four loops are there to help us. Let's see how. First, let's write a four loop that iterates through the list of waypoints and prints the arrival message and the departure message for each waypoint. In between these two print statements, let's write more print statements for each of the tasks that should be performed at a given location. When we execute the cell, we can see that the output matches the to do list. Now, to make sure that everything is clear, we'll break down how this code works step by step. When the program reaches the header of the four loop for the first time, Biton sets the waypoint loop variable to Granite falls crossing. Entering the body of the loop, PyTon prints the granite falls crossing arrival message, followed by each of the tasks, and then the granite falls crossing exit message. Then in the next loop iteration, PyTon sets the waypoint loop variable to starlight meadow and repeats the corresponding print statements in the body of the loop. The loop variable waypoint is similarly updated at the beginning of each of the remaining iterations. At the end of the last iteration of the loop, when the waypoint loop variable is set to Pine Ridge summit, Python returns to the loop header, notes that there are no more items to iterate through and exits the loop. This works fine. Our code is a lot more compact than if we had written all 30 print statements manually. But we can actually do better. Notice that in the body of the Four doop, our code is manually iterating through the indexes of the tasks list. If there were many more tasks, this would be very tedious. Thankfully, these repetitions can be eliminated by writing another four loop within our first four loop. For the record, we call a loop located inside another four loop, a nested loop. Let's see how we can improve our code with a nested four loop. To iterate over all the tasks at a given waypoint, let's create a for loop where for each task in tasks list, we print the name of the task. After executing the cell, we see that the output again matches what Jamie and Pike plan to do on their hike. Now, I know, understanding the execution flow of a nested loop can be challenging. For that reason, let's trade this code for a few iterations. As before, when Python first reaches the outer loop header, the waypoint loop variable is assigned the string granite falls crossing. Then Python moves to the outer loop's body and prints Granite Falls Crossings arrival message. Next, Python moves to the header of the nested loop. At that point, the loop variable task is assigned the first item in the tasks list, drink water. Moving into the body of the nested loop, PyTon prints the task. Then PyTon returns to the header of the nested loop and reassigns the task variable to the second item of the tasks list. Eat a snack. This task is then printed. The remaining iterations of the nested loop are similarly executed before Pyton exits that loop. Upon exiting the nested loop, Pyton executes the last line of the first iteration of the outer loop. Then Pyton returns to the outer loops header, where the variable waypoint is reassigned the value starlight meadow. And this cycle is repeated for all items in the waypoints list. To emphasize, the important takeaway here is that all iterations of the nested loop are executed before Python moves on to the next iteration of the outer loop. Awesome. You now have a handle on loops, and you've seen how they can be nested to solve complex problems. That being said, four loops are more difficult concept than the one we've covered before. For that reason, in the following exercises, we'll give you plenty of opportunities to practice. 34. For Loops - Exercise Solutions: In this workbook, you had the opportunity to practice using four loops in different scenarios. Additionally, you learned how to use multiple loop variables that enumerate and range functions, loop control mechanisms, and list comprehensions, which all make four loops even more useful. Let's break down the solutions. In exercise one, P A, we were given a playlist and needed to print out the title and duration of each song using a four loop. Because each element in playlist is a tuple with three elements, we unpacked our song loop variable into three individual variables. We then use these variables inside the print statement. This loop prints out each song in the list, along with its duration in minutes and seconds. In Part B, we added a minutes and seconds counter to our code from part A to calculate the total duration of all songs in the playlist. Inside the loop, we incremented the total minutes and total seconds variables to account for each song's duration. Then after the four loop, we extracted the number of full minutes from the total seconds variable using the floor division operator and added it to the total minutes variable. Next, we use the modulus operator to calculate the remaining seconds and reassign that value to the total seconds variable such that this value won't ever exceed 60. Finally, we printed out the total duration. Moving to exercise two, we were given a playlist of classic songs and needed to determine which songs in the playlist were by the Beatles and create playlists accordingly. For this, we created two empty lists, one for the Beatles songs, and one for other songs. Creating these empty lists outside the for loop ensures that we don't override the lists on each iteration of the loop. In the loop body, we unpacked the song tuples two items into the title and artist variables. We then used a conditional statement to determine whether the artist is the Beatles. If so, then we appended the song title to the Beatles Songs List. If not, we appended the song title to the other songs list. Finally, we printed out the two lists of songs. In exercise three, we learned how to use multiple loop variables to unpack items of a collection directly in the four loop header. In part A, we were given a playlist of popular songs and asked to print a report with the song information. To do this, we used multiple loop variables to unpack the song name, artist, and album information stored in each tuple of the list. Finally, we use these variables to print out the song information. In Part B, we were given lists of songs, minutes and seconds and asked to print each song along with its minutes and seconds duration. Since the three lists are indexed in the same order, meaning the items at the same position in each list are related, we used the zip function to combine the lists. Using multiple loop variables, we immediately unpacked the song, minutes and seconds data in the loop header. Finally, we use these variables to print out a useful message. In Part C, we needed to print out the same lists as Part B, but this time, assigning a number to each song. To do this, we built on our code from Part B and added the counter variable song num. Initially, we set it equal to one so that we may start numbering the songs from there. We kept song num updated by incrementing it at the end of each loop iteration. With this modification, we have numbered each of our songs. In Part D, we saw how the enumerate function can simplify our program from Part C. Instead of creating a separate counter variable, we passed our zipped lists into the enumerate function. Then, we created the iteration variable song num to capture the index returned by the enumerate function. Because the data we passed into the enumerate function is a zipped list, the second item returned from the enumerate function will be a tuple containing the song, minutes and seconds data. We directly unpacked this information in the header using the song, minutes and seconds variables. Note that we obtain the same output as in part C, but the current version of our code is more concise. In the last part of exercise three, we were provided with a list of tuples, each containing multiple items. Our task was to generate a report that extracted and displayed only the song title and its year of release. Since we were given a lot of unnecessary information about each song, we instead used underscores in the loop header as placeholders for the values we did not intend to use. This is good programming practice, since it makes obvious that this data is not used within the body of the loop. Moving to exercise four, we were given a top ten playlist and needed to print the first five songs in the list. To print just the first five songs, we use the range function with the argument five in the loop header. This caused the loop to iterate five times, sequentially assigning zero, one, two, three, and four to the loop variable I. Inside the body of the loop we used I to index our lists and retrieve the corresponding song. Note that I is a common variable name that programmers use to represent an iteration counter. With this code, we obtained the first five songs in the top ten list. In Exercise five, we were given a list of album information. Our task was to print each album and artist along with the songs in that album. To do this, we needed to use a nested loop. The Outer Loop unpacks the album, artist and song information for each item in the album's list. Using this information, we printed out the artist and album inside the outer loop. Then to print out each song in the songs list that we unpacked in the outer loop header we needed to create a nested loop. This inner loop prints out each song in the songs list before the outer loop moves on to the next iteration. The output of this code is the album and artist followed by each song in that album. Moving to exercise six, P A, we were given a party playlist, where some of the song titles contained the word California. We needed to print only the songs in the playlist that did not contain the word California in the title. For this, we created a loop with the variable song to capture the song name and a placeholder for the song duration, since we don't need that information here. Then inside the loop, we tested if the song name contains the substring California using the in keyword. This statement we evaluate to true if the substring California is found anywhere within the song title. If the song name contains California, we want to move immediately on to the next iteration of the loop without executing the remaining lines of code in the loop body. We use the continue keyword. If the song name does not include California, it will be printed. As a result, none of the songs in our output contain the word California. In Part B, using the same party playlist, we needed to print each song and the cumulative duration of the music played so far. However, once we have played music for more than 32 minutes, we need to stop printing songs. To do this, we built on our solution from part A to include an additional duration test. At the beginning of each loop iteration, we checked if total duration is greater than 32 to determine if it was time to stop playing music. If it was, we used the break keyword to immediately break out of the loop and stop printing songs. If not, then we continued to our California test. If that test passed, then the song name was printed and the total duration was incremented to account for the song being played. The output indicates that the song Livin' on our Prayer started playing before the 32 minute mark of the party. Once that song ended, the next song was not played since total duration was now greater than 32 minutes. In Exercise seven, P A, we were given a playlist and used a four loop to create a list of song titles with more than 15 characters. Inside this loop, we tested if each song met the title length condition. If it did, we added the song to our long title songs list. Lastly, in Part B, we improved on our code from Part A by using a list comprehension. Remember, a list comprehension is comprised of several parts. It starts with the expression. Here, we just use the song name, since that is what we would like in the final Long songs list. Then the list comprehension specifies the item in the collection. The item creates the loop variable song that we used in the expression. The collection is the playlist we wish to iterate through. Finally, the list comprehension includes a conditional statement. This conditional statement filters out songs with 15 characters or less in their titles. As a result, we obtained a list of songs with titles longer than 15 characters. Great. You've now had extensive practice using four loops in various scenarios and explored using new concepts that enhance their functionality. In the next video, we'll introduce a new data type, dictionaries. Four loops are especially powerful when working with dictionaries. So rest assured, you'll have plenty more opportunities to practice using four loops in the upcoming dictionaries exercises. 35. Dictionaries: In previous lectures, we learned about collections such as lists and tuples. Among other things, we learned that the items of these collections are indexed using consecutive integers, zero, one, two, and so on. In many applications, indexing the items using consecutive integers is totally appropriate. However, in other instances, we may need more flexible indexing options. When more flexibility is needed, PyTon provides a different type of collections called dictionaries. In this video, we introduce the concept of dictionaries and illustrate why they are sometimes preferable to other types of collections. Suppose you want to collect and store the email addresses of your three best friends, Bob, Wendy, and Cecilia. To achieve this, we can use the tools we learned in the previous lectures and create a list of email addresses. This works in the sense that we have effectively stored the data. But the way in which the values are indexed is not as informative as it could be. For example, suppose that at some point in the future, you consult your list to retrieve Cecilia's email address. Well, that might be more difficult than it should. Is Cecilia's email the zero first or second element in the list? Is it Cecilia who loves bunnies or is it Bob? Who still uses hotmail in the 21st century? Truly, we are left with more questions than answers. Indeed, this collection would be more informative if the values were indexed by the name of our friends instead of some arbitrary integers. And this is exactly what PyTon dictionaries allow us to do. Creating a dictionary starts with an empty pair of curly brackets. Then within those brackets, we pair a key with a value by joining the two with a column to add more key value pairs to the dictionary. Repeat the same steps, separating every pair with a comma. Once the dictionary has been created, we can retrieve information from it in a very intuitive way. For example, to access Cecilia's email, follow the name of the dictionary with brackets. Then instead of specifying the index of the element as we did for list, write the key Cecilia in between the brackets. And Tara, we have successfully retrieved Cecilia's email address from the dictionary. As a side note, we can also retrieve elements from a dictionary by using the G method. This method takes a key as an argument and returns the corresponding value. As you can see, when using a dictionary, there is no need to remember some abstract index to access the information we want. For that reason, dictionaries often provide a more intuitive way to organize information. Now that we have covered the fundamentals of dictionaries, let's make a few observations. First, the keys of a dictionary must be unique. In the context of our example, this means that we could not add another email address associated with the key Cecilia. As you can see, when the same key is included twice in the dictionary's definition, one of the two key value pairs is rejected. But this restriction does not extend to the values of the dictionary. The values of a dictionary can be duplicated. For example, if we create another dictionary to store the physical addresses of our friends, giving Cecilia and Wendy the same address is not a problem. Next, various data types can be used as keys and values. But as far as keys are concerned, strings are by far the most commonly used data type. Accordingly, we'll only be using strings as dictionary keys in this course. As far as values are concerned, a wide range of data types is used in practice, such as integers, floats, booleans, lists, and even dictionaries. You will get to explore some of the possibilities in the exercises. In the next video, we will explore additional operations and methods on dictionaries. Moreover, we will see how dictionaries can be used to store complex data structures, a very useful feature in practice. I'll see you there. 36. Dictionaries - Guided Examples: After a short but restful night of sleep, Jamie and Pike are getting ready to make the trek back down the mountain. As they're about to leave, Jamie asks Pike if he could document their journey back home. She would like him to prompt her with a few questions every 3 miles and record her answers. Pike enthusiastically agrees and creates a system to organize Jamie's responses in his notebook. First, Bike creates journal entries for the miles at which he needs to ask questions to Jamie. Then under each mileage entry, Bike writes the questions he must ask Jamie. That's a great way to organize information. If you look closely, you'll notice that Pike's organizational system appears to have a key value structure, albeit with an extra layer of keys. In this scenario, the mile markers are obviously keys, but the questions also appear to be keys. Interesting, how are we going to represent that in Piton? Here's a hint, just like we can create a list of lists. It is also possible to create a dictionary of dictionaries. That's how we'll get the extra layer of keys. Let's see how it's done. We start with an empty dictionary and then define the mileage keys. Next, we assign the values associated with each mileage key. In Pike's organizational structure, the value associated with a given mileage key is a group of question answer pairs that can themselves be represented with a dictionary. Because we do not know Jamie's answers at the moment, we will initialize the answer to each question with an empty string. By copying the question answer dictionary for the other mileage keys, we recreate Pike's organizational structure. This method for creating a dictionary of dictionaries works. But all the copy pasting is somewhat cumbersome, would you agree? When programming, if you find yourself copying multiple lines of code, there's likely a more efficient way to achieve what you want to do. In what follows, we will see how to build our dictionary of dictionaries iteratively using four loops. But before we get going, we need to discuss how to add an item to an existing dictionary as it is an important building block. For example, let's say we have an empty dictionary named my dictionary, and we want to add to it the key value pair, My number three. This can be done by assigning the value three to the new key, My number. If you'd like to add more key value pairs to your dictionary, no problem. We can similarly assign additional key value pairs to the dictionary. Okay, with that out of the way, let's see how we can cut down on the copy pasting and build our dictionary using a loop. We will proceed in three steps. First, we must create the empty Trilog dictionary and define the list of mile markers and questions we want to use as keys. Second, we use a first four loop to create the outer layer of keys. More specifically, we write a four loop that iterates over the mile markers and assign an empty dictionary to each key. This point, we have created the outer layer of keys. The third and final step is to create the dictionary's inner layer of keys. We will do this by creating a nested four loop to iterate over the items of the questions list. In the body of our nested loop, we assign an empty string to all the mileage question keys. Executing the code, we can see that we have indeed replicated the original dictionary. The syntax of the line of code in the body of the nested loop works just like it did in the context of multidimensional list. More precisely, Tra Log Miles selects the dictionary associated with the current mileage number key. For example, during the first iteration of the outer loop, this refers to the mile three dictionary. The second bracketed term referenced the key of the nested dictionary to which we want to assign the empty string. This implies that during the first iteration of the nested loop, this key is assigned an empty string. Note that by using four loops, we have created our dictionary of dictionaries with much less effort than typing out each individual entry manually would have required. Moreover, the four loop approach is more scalable. We can add another mileage marker or another question to our dictionary without making any changes to the four loop. Awesome. Jamie and Pike are now ready to begin their descent. After working their way through some steep and treacherous trails, our hikers arrive at mile three. Right on cue, Pike asks Jamie how she is feeling if she has seen any cool wildlife and how the trail conditions were. Jamie responds that she is feeling energized, that she saw two elk and moose, and that the trails were rocky and steep. To update our dictionary based on Jamie's answers, we first write the name of our dictionary, followed by the mile three key. This gives us access to the corresponding dictionary of questions and answers. Then we write the key of our first question for which we want to update the answer and assign the corresponding value. We can then similarly update the answers to the other two questions. Executing the cell, we see the updated values of all the questions associated with mile three. Wonderful. After recording Jamie's answers, the two adventurers continue their trek down Pine Ridge Mountain. The trail between mile three and six is much less rocky and winds through a dense forest. Jamie even spots a large bear at the bottom of a ravine. As they cross the mile six milestone of their trek, Pike once again, asks Jamie the questions on the list. Slightly exhausted, Jamie still finds the energy to answer Pike's questions. Jamie let him know that she is feeling tired and hungry, that she saw a bear and that the trails were covered in roots and overgrown. As you have probably noted, separately typing out each update to our dictionary is somewhat cumbersome. When we previously recorded Jamie's answers, we performed three separate assignments. That's fine, but in some cases, we may want to be able to update multiple key value pairs at once. In such situations, the update method can make our lives easier. This method takes a dictionary of the key value pairs to update as an argument and modifies the dictionary accordingly. Executing the cell, we can see that all of Jamie's mile six answers have been added to the trail log in a single statement. Once Jamie's answers have been recorded, our adventurers resume hiking. On the last leg of their journey, the trail conditions improve significantly. As a bonus, Jamie sees two bison in the distance as they near the trailhead. When the pair reaches the end of the trail at mile nine, Jamie anticipates Pike's questions and tells him that she feels tired but accomplished. She also notes that she saw two bison and that the trails were well maintained. In our code, we can once again use the update method to add this new information to our trail log. But instead of manually typing out each question key, which provides the opportunity to make a typo, we can index our questions list. Not only is this less error prone, but it saves us some typing, executing the cell, we see that the questions associated with the key mile nine have been updated. Awesome. You now understand how dictionaries work and how to interact with them. In the following exercises, you will practice using dictionaries in various contexts and learn about a few more useful methods. 37. Dictionaries - Exercise Solutions: In this workbook, you got hands on experience with using dictionaries to organize and structure information. You also explored how powerful four loops can be when working with dictionaries. Now let's go over the solutions together. In exercise one, Part A, we were given information about three art pieces and needed to store that information in a dictionary. To make it easy to look up artworks by their name, we set up the dictionary with the artwork names as keys. For each artwork, we included the artist and genre information by creating a nested dictionary with these attributes as values. This way, all relevant information for each artwork is neatly organized and easily accessible. In Part B, we were provided with additional art pieces to add to our dictionary. Instead of manually typing out all the information, which would be quite tedious, we have leveraged a four loop along with the provided lists to efficiently and programmatically build the art gallery. This approach saved time and reduced the risk of errors. There are at least two ways to create a dictionary from the given lists. First, we use the range function, which generates a sequence of numbers from zero up until the length of the provided lists. We then use these numbers to sequentially access the data at the corresponding indexes in the lists, creating key value pairs for our art gallery dictionary. Alternatively, we took advantage of the ZIP function, which neatly combines the three lists together. By unpacking the data directly in the four loop header, we were able to create key value pairs for our four loop dictionary in a more concise and readable way. In part C, we were given two more artworks and needed to add them to our art gallery dictionary. The best way to do this is using the update method, since it allows us to make a single method call to update our dictionary with both new entries. We passed in the new entries as key value pairs, and Python added them to our art gallery dictionary. Alternatively, we could have used index notation to create new entries. However, this approach comes with a bit more overhead as we need to first initialize the empty dictionaries before assigning each value separately. While this is a perfectly valid method, the syntax is a bit more cumbersome compared to the update method. In Exercise two, Part A, we were tasked with printing the names of all of the art pieces in the art gallery dictionary using just two lines of code. To achieve this, we use the Keys method along with a four loop. The Keys method gave us access to the names of the artworks, and we then printed each name within the loop's body. This approach efficiently displayed all of the artwork names with minimal code. In part B, we were asked to print the artist names associated with each work by iterating through the dictionary values. The value associated with each key in the art gallery dictionary is another dictionary. To access the artist's name, we retrieve the value associated with the artist key within this nested dictionary. This allowed us to print the artist's names for each artwork efficiently. In Part C, we were tasked with printing the name of the artwork and its corresponding artist. To do this, we use the items method to unpack each key value pair from the dictionary into two loop variables, one for the artwork name and one for the details. Inside the loop, we printed the artwork name and access the artist value from the details dictionary to include it in the output. This approach allowed us to neatly display each artwork alongside its artist. Next, in exercise three, we needed to check our art gallery dictionary to see if it contained the artwork called American Gothic. To determine if American Gothic is in the Art Gallery dictionary, we created a simple conditional statement. The conditional expression used the in keyword to check whether the work existed in the dictionary. With this conditional block, we obtained that American Gothic is in the Art Gallery. In Exercise four, Part A, we were required to remove American Gothic from the dictionary. We accomplished this by using the pop method, which removes the specified key and its associated value from the dictionary. The cell output confirmed that the American Gothic key value pair was successfully removed. In part B, we needed to remove two works from our dictionary and print their information. We accomplished this by using a four loop to iterate through our loaned art list. For each work in the loaned art list, we removed it from the art gallery dictionary by passing the work name as an argument to the pop method. Since the POP method returns the value associated with the removed key, we stored that value in a variable called removed art. This value is a dictionary that contains the artist and genre information. In the print statement, we displayed the name of the work using the loop variable work, and we printed the associated artist and genre information stored in the removed art dictionary. Because the removed art variable contains a nested dictionary, we use the G method to specifically access and print the artist and genre values. This approach allowed us to cleanly remove the works and display their details. Finally, in Exercise five, we tackled some harder problems. In Part A, we used a list comprehension to streamline the process of finding and printing all of the works created by Leonardo DaVinci in our art gallery dictionary. Let's break down how this list comprehension works. Recall the structure of a list comprehension. First is the expression. This determines what each item in the resulting list will be. In our case, the expression is the piece variable representing the artwork names. Second, we define the loop variables. These are the variables we use to iterate over the collection. Here we have piece and details where piece refers to the artwork name and details refers to the nested dictionary containing the artist and genre information. Third, is the data we are iterating over. In this instance, it's the items in the art gallery dictionary. Finally, we have the condition which filters the items based on a specific criteria. We use the details loop variable to check if the artist's name for the current piece is Leonardo Da Vinci. If this condition is met, the work is included in the final results list. If not, it's skipped. When the list comprehension finishes executing, we're left with a list of all the works created by Leonardo DaVinci. This concise approach reduces lines of code and makes it easier to focus on the essential logic of the task. In Part B, we needed to count the number of art pieces by each artist, and we did this using 24 loops. In the first loop, we iterated through the values of the art gallery dictionary to find the artist for each work. We then checked if the artist was already in the artists summary dictionary. If they were, we incremented the value associated with their name by one. But if they weren't, we added a new entry for that artist in the artist's summary dictionary and set their count to one. In the second loop, we use the items method to iterate through the keys and values of the artists summary dictionary. In the loop header, we unpacked the output of the items method into two variables, the artist's name and the number of works associated with them. We then printed this information, giving us a clear summary of how many artworks each artist had in the collection. Awesome. You've now gained substantial experience working with dictionaries and sharpened your skills working with four loops. In the next video, we'll explore how to make our code more interactive as we dive into handling user input. 38. User Input: In this course, we have so far focused on writing programs that do not interact with the user while the program is running. Essentially, we've been running code and waiting for the output to show up. However, in practice, user inputs are often useful for creating dynamic and responsive programs. In this video, we'll study how to make our program more engaging by integrating user inputs. I'll start by introducing the input function, which is the primary way to request user inputs in PyTon. The role of the input function is to prompt the user to enter data, which our program can then process. For example, let's write a simple program asking the user to provide their name. This can be done by simply calling the input function as follows. Fine. But without any context, it might be difficult for the user to understand what information the program expects. To help the user, we can pass as an argument into the input function, a message to be displayed before the input prompt. Much clearer. Once the user has typed in the data and pressed Enter, the user's input is immediately returned to the program and displayed in the output box. That's cool. But if we ask a user for their input, it's likely because we want to do something with that input in our program. To collect the user's input, we assign the return value of the input function to a variable. From there, you may use the variable in the rest of the program like any other variable. Great. Now that we know the fundamental features of the input function, let's make a few additional remarks. First, when Python executes the line containing the input function, the program pauses and waits for the user's input. Once the user has submitted their input, the execution of the remaining lines of code resumes. Second, it is best practice to write clear and precise text prompts so that the user knows what information they are expected to input. Third, regardless of the value the user supplies, the input function always returns that value as a string. If, for example, we write another program to ask the user for their age and they input a number, this number is returned as a string. This is not really an issue in practice because numbers represented by Python strings can always be converted back to the appropriate data type inside the program. It's just something to be mindful of. Relatedly, it is good practice to immediately cast the user's input to the expected data type. This way, we can safely assume that the data is of the appropriate type in the remainder of the program. Finally, to provide a smooth user experience, it is best practice to provide some confirmation that the input was received. Great. As you've seen, user inputs make programs flexible by allowing the user to guide the program's execution in real time. However, user inputs sometimes create additional programming challenges. For example, users may provide unsuitable inputs. In the next video, we will study how to handle those unexpected inputs and make our programs more robust. 39. Error Handling: In the previous video, we saw how to request user inputs during the execution of a program. In many applications, user inputs are necessary to determine the execution flow of a program. However, users can input anything in an input box, which can lead to unexpected behavior or errors. To make our programs more robust and user friendly, we need to handle these errors gracefully. In this video, we will see how to use PyTn's error handling mechanism to manage and handle those errors effectively. Let's start with a simple example to show what happens when we don't handle errors properly. Consider this program that prompts the user to provide two numbers and returns their cotent. This program works as intended as long as the user provides valued inputs. However, if the user enters something unexpected, then the program crashes. We can safely assume that for the average user, the message on screen is Gibberish. Receiving an output like that results in a poor user experience. To improve the user's experience, we need to handle these errors, also known as exceptions so the user can understand why their input was incorrect. To catch and handle the SPSC errors, PyTon provides the try and except keywords. We use those keywords as follows. Under the try statement, we intend the code we are concerned could cause an exception. If a line of code in the tr block causes an error, Pyton moves down to the except block without executing the remainder of the trilock. In the except block, we write code that either addresses the error or outputs an instruction for the user. On the other hand, if there is no error in the execution of the tri block, the except block is skipped. Let's implement a tr except block in our tient calculator program. We start by writing the tri keyword above the potentially problematic code and indenting the lines of concern. Then we write the except keyword on the same level of indentation as the tr keyword. Under this keyword, we write the code we want to execute if an exception occurs. In this case, it suffices to print a simple statement informing the user that an error has occurred and providing instructions about how to fix the error the next time the user runs the program. Let's test our modified code. When the user provides numbers, the program delivers the same output as before. But on the other hand, if the user inputs non numeric data, the program now handles the error more gracefully. The program's output tells the user that something went wrong and that they should input numeric data next time they run the program. However, inputting a word instead of a number is not the only mistake the user can make. For example, if we rerun our program and input zero as the denominator, our program outputs the same error message. But in this case, the two inputs are numbers. This error message is confusing. The issue here is that we attempted to divide 12 by zero. This produced an error which was then handled by our exception block, which in turn printed the error message on the screen. Wouldn't it be better if our program could handle non numeric data and division by zero errors separately? Well, that's possible to catch and handle different types of errors separately. We need multiple except blocks. For each except block, we must specify the type of error the block should handle. To determine the type of an error, we can replicate the exception in a different cell. The error is given as the first line of the output. In this case, the exception type is value error. So this is what we must write in the except statement that handles this exception type. Similarly, to determine the type of exception associated with division by zero, let's replicate the error. We find that the exception type is zero division error. Let's add that information to the second except statement and change the message in the blocks body to be more informative. Great. In summary, this new version of our program gently directs the user to input a number if they mistakenly entered something else. Moreover, the program instructs users to choose a non zero denominator if they made that mistake. Finally, if the numerator and denominator are valid, the program calculates the tent. Now, this modified version of our program provides a much better user experience. Great. You now know how to write robust programs that accept user inputs. In the next video, we will explore a few more situation where good error handling can improve user experience. 40. User Input and Error Handling - Guided Examples: Jamie and Pike's two day hike was a great success. Sure, I took them a few days to recover. But now that they are well rested, the two are eager to attack a more ambitious trail. After reviewing various options, Pike proposes a five day hike that will take them to a different campground each night. Given this adventurous length and anticipated intensity, Jimi needs to ensure that she carries the right amount of water at the beginning of each day. That is enough to stay hydrated, but no more than necessary or she will needlessly carry extra weight. Thankfully, Pike can help. He inquires about the duration of Jamie's hike to calculate the required amount of water. Similarly, we can use Piton to ask a user to enter the length of their hike using the input function. From experience, Pike knows that 24 ounces of water per hour is what Jamie needs on an average hike. Therefore, we can answer Jamie's question by casting the user input to a float, multiplying the resulting number by 24, and printing the result. Jamie informs Pike that she expects to be hiking for about 6 hours a day. Pike takes our input and Oops, it looks like Pike is unable to process Jamie's answer. Moreover, the error message that Pike returned is confusing to Jamie. This gibberish doesn't mean anything to her. All right. Pike Waters calculation program doesn't handle errors very well. Unfortunately, our PTN program doesn't fare much better. We receive a similar error message if we execute the code and provide the same input. However, we know how to address this issue in PTN. To handle exceptions of the value error type, we know that we can indent the potentially dangerous code under a try statement and then under an accept statement, write a helpful error message. Re running the cell and providing the same input as before produces a helpful and informative error message. Similarly, after a little bit of introspection and self improvement, Pike was able to implement better error handling. So he invites Jamie to give it another try. Not knowing what was wrong with our first input, Jamie gives Pike the same input again. But now, in it's upgrade aversion, Pike's error message is much more helpful to Jamie. She learns that she must input a numerical number of hours. Provided with a valued input, Pike responds that Jamie needs to bring 144 ounces of water with her. This is amazing. Jamie will now be able to delegate water calculation to Pike. User input and error handling are useful tools for creating dynamic programs in PyTon. While we have covered the basics here, such as using the Tri and except blocks to handle unexpected inputs, there's a lot more to cover. The upcoming exercises will give you hands on practice with these concepts. For those interested in learning more, there's additional resources available in the appendix. 41. User Input and Error Handling - Exercise Solutions: In this workbook, you've practiced asking users for input and managing any errors that might come up. Let's break down the solutions. In Exercise one, Part A, we needed to translate English words into Zonian using the language translator dictionary. To achieve this, we first ask the user to input the word they want to translate. Next, inside the Tri Block, we attempt to find the word in the language translator dictionary and print the translation. If the word lookup fails, we handle the error in the except block. This ensures that the program handles missing translations smoothly. The final program prompts the user to enter an English word and then provides the Zonian translation. In Part B, we focused on the else clause and used it to improve our code from Part A. Since the word lookup might cause an error, we keep that code inside the trilock. Because we only want the print statement to execute, if the word lookup succeeds, we move it to the else block. Remember, the else Block ensures that the code within it only runs if the entire triblock succeeds. In Exercise two, part A, we needed to create an English to Zalonian unit converter program. To do this, we ask the user to enter the earthly unit they wish to convert. Within a triblock we attempt to retrieve the conversion factor from the measurement translator dictionary using the provided unit and the string conversion factor as keys. If the lookup fails, we catch the resulting key error in the except block. Next, since the program should only ask for the quantity to convert, if the user provides a valid unit, we embed a second error handling block inside the first else block. The nested except block handles the value error that will occur if the user's input can't be converted into a float. Finally, the LSE block calculates the conversion and prints the result. Writing the quantity input logic here ensures that the conversions are only attempted when both the unit and quantity inputs are valid. The final program prompts the user for an earthly unit and quantity then outputs the corresponding Zalonian conversion. In Part B, we improved our code from part A by standardizing the user inputs. We use the lower and strip methods to clean up the inputs, ensuring that any extra spaces or variations in capitalization won't cause issues. This makes our code more robust against improper user inputs and provides a smoother user experience. In exercise three, P A, we needed to convert kilometer distances to their Zalonian equivalent. To achieve this, we first ask the user to input the number of distances they wish to convert. We standardize this input and handle the value error that may occur during the integer cast. Next, we embed the remaining code inside an else block to ensure it only runs if the user provides a valid input. Inside the else block, we create a four loop to iterate through the number of distances the user specified. We pass the user's previous input into the range function to generate a sequence of numbers from zero up to but not including the number of distances. Additionally, we use a place holder for the loop variable since it's not used in the loop body. Within the loop we include an error handling block that asks the user to input a distance and attempts to cast it to a float. If the conversion fails, the resulting value error is caught in the except block. If it succeeds, the valid quantity is converted and printed. The final program asks the user to input the number of distances they want to convert and then asks them for a distance to convert that number of times. In Part B, we enhanced our English to Zalonian translator to accept multiword phrases. To do this, we first ask the user to input an English phrase and then standardize the input. Next, we use the split method to break the phrase into a list of individual words. Then we iterate through this list of words with a for loop. Inside the loop, we attempt to translate each word and append the translation to a translation list. We also include an except block to handle the key error that occurs if a word is not found in the dictionary. If a word can't be translated, the program breaks out of the loop early, and as a result, the translation list will not be as long as the words list. This is why we have to check to see if both lists have the same length. If they do, that means that the entire phrase was translated. And if they don't, that means that at least one word couldn't be translated. This approach ensures complete translations while handling untranslatable words effectively. The final program prompts the user for an English phrase and then outputs the entire phrase translated into Zalonian. In Exercise four, we saw a few more advanced concepts. In Part A, we created a Zilonian to English translator. Translating from Zonian to English using the language translator dictionary is a bit more complex than the reverse. This is because Zilonian words are stored as the values in the dictionary, so we can't directly look them up like we can with the English words, which are keys. Instead, we used a four loop combined with the items method to iterate over all the key value pairs in the language translator dictionary. During each iteration, the program checks if the current dictionary value matches the Zonian word we want to translate. If a match was found in the dictionary, we print the English word, which is the dictionary key that corresponds to the Zonian word, which is the dictionary value. We also set the word found variable to true and break out of the loop. If a loop finishes without finding a matching Zonian word, the word found variable remains false. We check the value of the word found variable to determine if the translation was successful. If it's not, we raise a custom value error, catch it in the except block, and provide a helpful error message. The final program takes the Zonian word as input and translates it to English. In Part B, we improved our Zonian to English translator to accept phrases. This problem combines concepts from exercise three, Part B, and Part A of this exercise. Like in Exercise three, Part B, we split the input phrase into individual words using the split method and iterate through each word with a loop. Within this loop, we write another loop to search the values of the language translator dictionary, similar to Part A of this exercise. After the inner loop finishes searching for the Zonian word in the dictionary, the program checks if the word was found. If the word wasn't found, we raise a value error with a custom informative message. To handle the error, we use the as E notation to capture the custom error message and print it within the except block. Finally, if all of the words were successfully translated, we print the complete translation. Now, the program allows us to input Slonian phrases and get back their English translation. In Part C, we needed to convert multiple measurements at once. To do this, we first ask the user to input the measurements as a comma separated list. We then split this input into a list of individual measurements. Using a four loop, we iterate through each measurement in the list. Inside the loop, we attempt to split each measurement into its quantity and unit. Next, we try to cast the quantity to a float and look up the corresponding unit in the measurement translator dictionary. If the unit isn't found, we use the rays keyword within the tri block to create a custom error. Finally, we convert the quantity from earthly units to Zonian units and print the results. The final program takes a series of comma separated earthly measurements and converts each one to its Zlonian equivalent. Awesome. Now you have a solid understanding of how to take user input and handle the resulting errors. In the upcoming videos, you will learn how to leverage while loops to further improve the user interactions in your program. 42. While Loops: In previous videos, we saw how powerful four loops can be to automate repetitive tasks. However, as helpful as they are, four loops have limitations. An important limitation of four loops is that the number of times the loop should be run must be known at the time the program enters the loop. Unfortunately, in many situations, it is not possible to know how many times a loop should be run before we run the code. For those situations, four loops are the wrong tool for the job. Thankfully, another type of loops called Wil loops can be used instead. In this video, we introduce this notion of wild loops and discuss when they should be used instead of four loops. To illustrate the limitation of four loops, let's recall the example of the store owner who is discounting inventory items. In this example, the store owner wants to discount the prices in a predetermined list. The length of the price list is known before the loop executes, and it determines the number of iterations the loop will perform. For that reason, using a four loop is appropriate in this context. But now let's modify this example slightly. Suppose the store owner doesn't know the list of items that must be discounted when they run the program. Instead, they would like to manually enter the price of the items they want to discount as they process the inventory. Moreover, let's assume the store owner doesn't know how many items they will have to discount. All right. Let's see how to modify our code to satisfy the store owner's requirements. Since the store owner no longer provides us with a predetermined list of prices, we should remove it from the program. This immediately creates an issue with the for loop. The iteration list no longer exists, so we can no longer use the iteration variable. But that's okay. We can still instruct PyTon to repeat a piece of code by replacing our for loop with a while loop. A while loop executes the piece of code in its body repeatedly as long as a control condition specified in the loop header is true. Finally, let's make the necessary modifications to the loop's body. Remember, the store owner wants to be able to input the prices to discount. So let's write an input statement. Great, to familiarize ourselves with the execution of a wild loop. Let's run our program and trace a couple of iterations. Because we assign true to the should iterate variable, the program enters the body of the Wil loop and we are prompted to enter a price. When we enter the price, the program applies the discount and prints the sale price. Having reached the last line of the Wil oops body, the program returns to the header and tests whether the control condition is true. Since the value of the shoot iterate variable is still true, the control condition is also true, and the program proceeds with a second iteration of the loop. This explains why we have been prompted to enter a second price immediately after submitting the first one. This is great. No need to rerun the code to discount additional prices. That's the power of Y loops. But the keen eyed among you may have noticed that there is a slight problem with our program. If you haven't noticed it yet, think about the execution of our loop for a second. When exactly will our program exit the loop? Well, since we are not modifying the should iterate variable in the loop's body, the control condition in the loop header will always be true. This in turn implies that the program will never exit the loop. Oh, no, we have created an infinite loop. The user will be prompted to enter prices until the end of time. What are we going to do? Well, there is no need to panic. We simply need to design a mechanism to assign the variable should iterate to falls when we want to exit the program. A common way to achieve this is to instruct users to enter a specific input when they wish to exit the program. To implement this, we first test if the user input equals this special value. If it is, we reassign the value of the should iterate variable to false. If it is not, we calculate the discount, output the price, and move on to the next iteration as before. Awesome. Et's rerun our code to verify if it works as intended. During the first iteration of the wire loop, our program asks for a price. We input 24.58, and the program outputs the discounted price 17.21. If this is the only price we want to discount, we enter the exit value minus one, and the program terminates gracefully. Amazing. However, the way our program handles unexpected user input is less graceful. For example, if a user mistakenly inputs a string, the program crashes. Oh, not a great user experience. But we have seen this error before and we know how to handle it. So let's improve the user experience by indenting the dangerous code under a tri block and handling the value error in an except block. Nice. While the previous version of our program was allergic to cats and showed no mercy upon encountering that word, the new version of our code is much more forgiving. When the user makes a mistake, the program is able to recuperate and redirects the user to enter a valued input in a new input box. Much better. To conclude this video, let's take a step back and cement in our head the difference between four loops and wild loops. As you have seen in this video, an important limitation of four loops is that we must know how many iteration the loop will perform before its execution starts. This condition is satisfied in many if not most applications. However, there are situations where we cannot know how many iterations of the loop a program will need. This is often the case when working with user inputs and in some other contexts as well. In these cases, the indefinite nature of Wil loop iterations makes this type of loop the best choice. Wile loops are powerful tools that Python provides to write efficient and simple code. In the next video, we'll explore a different scenario where Wil loops can be helpful. 43. While Loops - Guided Examples: Jimmie and Pike are almost ready to head out on their five day adventure. To ensure she does not run out of water during the hike, Jamie intends to carefully track how much water she has left. Each time Jamie's thirsty, she'll tell Pike how much water she wants to drink, and Pike will calculate the amount remaining. Following Pike's previous recommendation, she will begin the first day of the hike with 144 ounces of water. Let's write a PyTon program that can accomplish Pike's task. We'll start by creating a variable to store the remaining ounces of water and initialize it to 144 since this is the volume of water JM starts our journey with. From there, our program must query the user for the amount of water they want to drink and adjust the ounces of water accordingly. Because it is difficult to predict the exact number of times the user will drink water, requesting the user's input within a while loop is the right thing to do. For now, we leave the control condition of the loop blank, but we'll return to it when we have figured out the body of the loop. Once the user has entered how much water they want to drink, we find ourselves in one of two situations. One possibility is that there is enough water remaining to drink the desired amount. In that case, we subtract the input at quantity, reassign ounces remaining, and print the result of our calculation. If that's not the case, the user can at most drink the amount of water remaining. Accordingly, we let the user know how much water they can actually drink, inform them that they are now out of water, and reassign zero to ounces remaining. Awesome. Now that we have built the body of the loop, let's move back to the loop's header to write the control condition. I will argue that the program should only ask the user how much they want to drink when there is still water left. Otherwise, it's just rude. Accordingly, as a controlled condition, we test if a strictly positive amount of water remains. As long as this condition is true, it is sensible to query the user. But when this condition is false, it is time to exit the loop. Now, of course, it is possible that the user completes their hike before running out of water. To enable the user to exit the program gracefully, we can invite them to input the value minus one to quit. When the user is allowed to enter an exit value, the first thing our code should check is whether the user input is the exit value. If it is, we output the number of ounces remaining and use the brake keyword to exit the loop. If not, we execute the remainder of the program as before. Note that a break statement is a convenient way to handle the user's request to quit the program. But as we saw in the last video, it is not the only way. Awesome. Jamie and Pike are now ready to hit the trails. About an hour into their hike, Jamie is feeling thirsty. The two pas as Jamie drinks 19 ounces of water. If we execute our code and enter 19 ounces, we obtain that there are still 125 ounces remaining. Jamie and Pike then hit the trail again and continue their trek. Along the way, Jamie drinks 25 ounces at the fork in the trail, 32 ounces at the top of a steep climb and 18 ounces while contemplating a waterfall. A few hours into the hike, the two stop for lunch, during which Jamie consumes another 27 ounces of the scarce liquid. An hour or so after lunch, the pair stops near a river to rest. Jamie tells Spike that she intends to drink 25 ounces of water. Unfortunately, that's a tad more than what's available. As a result, Pike let her know how much she can actually drink and stops querying her for more input. Thankfully, Jamie and Pike are only a few minutes from the cam site. They'll be able to refill when they reach their destination. As you have seen, Wi loops can greatly improve user experience for programs using user inputs. In the following exercises, you'll get the chance to practice using Wi loops to create programs with a pleasant user experience. 44. While Loops - Exercise Solutions: In this workbook, you practiced using Wile loops in more complex situations. Now, let's go over the solutions together. In exercise one, we created a program that asks for user inputs to track the number of apples in the inventory. First, the program asks the user to enter the number of apples they brought to the market. The input is then immediately casted to an integer for use in future calculations. The program then enters a Wile loop that runs as long as there are apples remaining. Inside the loop, the user is asked to input the number of apples sold in a transaction. Here again, this input is converted to an integer, ensuring that it can be used for future calculations. The apples sold and Apples remaining variables are then updated to reflect the number of apples left in the inventory. We then print the content of those variables. Once there are no apples remaining, the Wile loop exits. The final program prompts the user to enter the number of apples they brought to the market and then allows them to input the number sold until they sell out of apples. In exercise two, we wrote a program to track the quantity of wheat and barley acquired until the user has 20 units of each. To track the quantities purchased, we create countervariables. We then use a Wile loop with the condition wheat less than 20 or barley less than 20, ensuring the loop will continue as long as either the wheat or the barley variables are below 20. Inside the loop, we prompt the user to input the amount of wheat and barley they have acquired in a transaction. As an exercise one, we convert these inputs to integers so we can use them in future calculations. The wheat and barley counters are then updated to reflect the new totals and we print the current counts. The loop ends when both the wheat and barley variables reach 20 or more. The final program asks for user inputs to track the amount of wheat and barley acquired. In exercise three, part A, we wrote a program to manage the recruitment process for new guild members. Our goal was to recruit three members, but we didn't know how many candidates we would need to evaluate to reach that goal. We solve this problem using nested loops. After initializing the number of positions remaining to three, our program enters a while loop that runs as long as there are positions remaining. Inside this loop, we first set the trial passed counter for the current candidate. Next, we create a nested four loop to request the trial results from the user. We use the range function in the loop header to iterate through these two trials. Within the fore loop, we ask the user to input the result of the trial. If the candidate passes, we increment the trial's passed counter. After both trials are completed, we test if the trial's passed counter is equal to two. If it is, we have found a suitable candidate and the number of positions remaining is decremented. Otherwise, we indicate failure by printing a message. The final program allows the user to input whether a trial was passed, tracks the number of member spots remaining and exits once three members have been recruited. In Part B, we modified our code from Part A to accommodate the new recruitment rules. Our program now includes a new variable, trials attempted to track the running count of a candidate's attempts. The variable must be reset for each new candidate, so we place it inside the outer loop but outside the inner loop. Next, we use a Wile loop to test whether the candidate still has trials to pass and trial attempts remaining. This loop runs as long as the number of successes is less than two and the number of trial attempts is less than or equal to five. Note that this while loop may iterate as little as two times or as many as five times, depending on the candidate's success. Within the loop, we still ask for the trial result and increment the trials passed accordingly. However, now, we also increment the trials attempted. After the inner loop, we follow the same logic as in part A to determine if the candidate can become a guild member. The final program will exit once two members are recruited. In exercise four, we explored infinite loops. In Part A, we used the Wil true syntax to continuously prompt the user to input the number of jokes they sold. Inside this Wile loop, we increment the jokes sold variable based off the user input and print the running count. Since there is no exit condition, we have effectively created an infinite loop. In Part B, we fix that infinite loop problem by adding an exit condition and using the break keyword. Now, if the user enters negative one, the loop breaks and immediately stops running. If a user enters anything other than negative one, we still increment the jokes variable as we did in Part A. The final program will continue asking for the number of jokes sold until the user inputs negative one. In Exercise five, Part A, we use a while loop to remove items from an inventory list. The loop condition inventory is a shorthand way to test whether the list is empty. It's equivalent to using the longer n inventory greater than zero as a control condition. We then test whether the item is in the inventory. If it is, we use the remove method to remove it. If it's not, we notify the user. The final program will continue asking the user to enter an item until there are no items left in the inventory. Finally, in Part B, we created two equivalent programs to track the intraday profit of a user's merchant business. In the first program, we use a control condition to test if the current profit is less than the target profit. This condition ensures that the loop stops running once the user has saved enough money for the day. Inside the loop, we ask the user for the transaction details and then add the transactions profit to the current profit. After updating the current profit, we test whether it is below the target profit. If it is, we inform the user of their cumulative profit so far and output how much more is needed to reach the target. If the profit meets or exceeds the target, we notify the user that they have reached their goal. In the second program, we use the wild true syntax, combined with the break keyword to achieve the same outcome. Both programs will continue asking the user to input transaction information until the target profit is reached. Great. You've now seen how Wile loops can be used in combination with the concepts we've learned so far in this course. In the next videos, we will once again upgrade our programming toolbox by diving into one of the most powerful programming concepts, user defined functions. 45. User-defined Functions: In previous lectures, we've used several of PyTn's built in functions such as print, len and input. These functions helped us perform common tasks without writing the code ourselves and kept our programs organized and readable. Unfortunately, PTN was not built with all the functions that every situation requires. For example, if you're an architect who often needs to calculate the area of geometrical shapes, you're out of luck. There isn't in Bton a built in function that can calculate a triangles area or a rectangles area. Fortunately, PTN enables programmer to define their own function, which are called user defined functions. User defined functions are prepackaged pieces of code that can perform a given task such as calculating the area of a rectangle. In this video, you will learn how to define your own functions and explore how these functions can add value to a program. An architect has designed the floor plan of a new building called the zigzag. He now needs to calculate the area of the building's three zones to order the flooring. Unfortunately, the architect flunked his geometry class and never learned how to calculate a rectangles area given its length and width. Let's help him do his job by creating a Pyton function that does this calculation. In Pyton, the definition of a new function starts with the keyword death. This keyword is followed by the name we want to give to our function. When naming functions, choose descriptive names that reflect the function's role, just as you would for variables. Moreover, function names must follow the same naming rules as variables. In our example, the name rectangle area is descriptive of what we want our function to do and adheres to the four naming rules. So we'll go with that. Next, we follow the function's name with a pair of parentheses, between which we specify variable names for the inputs or function requires to perform its task. Since the length and width of a rectangle are required to calculate its area, we write variable names for these two inputs, separating them with a comma. We conclude the header of the function definition with a column. Next, in the indented body of the function, we write the operations necessary to calculate the rectangles area using the inputs. Here, we multiply the length by the width and assign the result to the area variable. While we've now calculated our functions desired output, we're not quite finished yet. Indeed, to make the calculated area available to the program that calls or function, we need to use a special instruction called a return statement. This statement consists of the return keyword followed by the data we want to output. Without a return statement, the result of our calculation will be lost when the function finishes executing. We'll soon say more about that. Awesome. Now that we've defined the rectangle area function, we can use it like any built in function throughout the rest of our program. To call our function, we write its name followed by parentheses containing the rectangle's length and width. At this stage, it is important to distinguish between the variable names in the header of the function definition and the values used in the function call. As you already know, the values passed into a function are called arguments. In this example, the arguments are 100 and 140. The variable names in the header length and width are called the functions parameters. Parameters are placeholder variables that receive the argument values when the function is called. To summarize. While both arguments and parameters refer to function inputs, arguments are the actual values used in function calls. Was parameters are the variable names used in function definition. Okay, now that we've clarified the terminology, let's run the program to see our rectangle area function in action, calculating the area of Zone one. We obtain 14,000 square feet. This probably doesn't come as a surprise for the math wizards among you, but for our mathematically challenged architect, this function is a lifesaver. He can now easily calculate the areas of any building zone without understanding the underlying mathematics. To the architect, the rectangle area function acts as a black box. Inputs are provided, outputs are received, and the internal calculations remain invisible. As we have seen with built in functions, this concept known as abstraction is a key advantage of using functions. By creating user defined functions, we can package a set of operations into a single reusable code unit. These custom functions can encapsulate operations of any complexity, improving code readability, and eliminating the need to rewrite common operations. Once created and tested, user defined functions can be used as black boxes with users focusing on inputs and outputs rather than the internal workings. However, to design and implement these functions effectively, programmers must understand PTon's function execution process. This includes comprehending how PyTon manages parameters and variables not only during a function's execution, but also after it completes. To illustrate this concept, let's trace the code that calculates the area of zone one. The initial lines of code define the rectangle area function. Once executed, PyTon recognizes rectangle area as a valued function callable anywhere in the subsequent code. The program then calls this function with the arguments 100 and 140. When this call occurs, PyTon first creates two variables, length and width, and assign them the values 100 and 140 respectively. Then PTN executes the function body, multiplying length by width and assigning the result to a new variable area. Finally, PyTon executes the return statement, passing the calculated area back to the program and discarding all variables created within the function, including the parameters. That's an important point. As a result, any attempt to access the length with an area variables outside the function will generate a name error. That's because PyTon considers these variables non existent once the program has exited the function. In contrast, if we include a print statement within the rectangle area function itself, PyTon successfully accesses and displays the value of the area variable. This behavior highlights an important concept in programming known as variable scope. In an upcoming lecture, we'll explore the intricacies of variable scope. But before we go there, let's focus on gaining some more hands on experience with how to define functions and how to use them. In the following video, we'll create a few more functions to gain an intuition for how and when to use them effectively in our programs. 46. User-defined Functions - Guided Examples: Jimmy and Pike have now completed the first day of their five day hike. As they settle down by a campfire, they reflect on the day's adventure. Jamie confides in Pike that the day's trek was more challenging than anticipated. They spend considerably more time on the trail and consume more of their food supplies than Pike had initially predicted. To make sure she has enough energy and supplies to finish, Jimmy would like to get better estimates for the remainder of their journey. Eager to assist, Pike prepares to refine his forecasting calculations based on Jamie's input. As we accompany him in the process, we'll see how functions can streamline code organization and readability. To generate more precise estimates, Pike will incorporate data on the hikes distance, temperature, and tearing difficulty in his calculations. Let's begin by estimating the expected hike duration. Under typical conditions, Jamie maintains a steady pace of 3 miles per hour, which serves as our baseline for calculating hike duration. However, challenging terrain or high temperatures can significantly slow Jamie's progress. To account for these variables, we need to calculate adjustment factors and modify our baseline estimate. Let's now calculate the total calorie expenditure of a hike. As a baseline, Jamie burns approximately 160 calories per hour in typical hiking conditions. However, challenging terrain ramps up Jamie's energy output, so we need to adjust this baseline rate. To calculate the total calorie expenditure, we first modify the hourly calorie burning rate based on terrain difficulty, then multiply this adjusted rate by the estimated hike duration. Finally, let's present our estimates in a clear user friendly format. Awesome. When we run our code, it generates precise estimates for tomorrow's hike duration and the corresponding energy expenditure Jamie can expect. And this is the desired output. This is good. However, the current structure of our code leaves room for improvement in terms of clarity and organization. We noted earlier, our block of code performs three distinct tasks. It calculates the hike duration, calculates Jamie's energy expenditure, and prints the results. To enhance the readability of our code, we'll refactor it by encapsulating the three main tasks into separate functions. This modular approach will clarify the code's purpose and flow. Let's start by creating a function called calc hours to estimate the time required for the hike. The calc hours function accepts three parameters. Distance the length of the hike in miles, temp, the ambient temperature in Fahrenit and terrain difficulty, the rating of the terrance difficulty on a scale 1-3. In the functions body, we copy the relevant lines of code to calculate the hike duration. The final line of the functions body originally assigned the return value to the variable adjusted hours. However, this assignment is unnecessary. We can instead directly instruct PyTon to return the calculated result. By eliminating the intermediate variable assignment, we've made our code more concise and efficient. With this function defined, we can simplify the first code block with a single call to the calc hours function. Note that when calling the calc hours function, we passed variables containing the values ten, 75 and two as arguments rather than passing the values themselves. When variables are used as arguments, Biton passes the values the variable contain to the function and assign those values to the corresponding function parameters. Here, it's important to understand that the variable names used in the function call don't need to match the parameter names in the function definition. For instance, if we rename the parameter temp to temperature in the function definition, the calc hours function still works as intended when called with the variable temp as an argument. In that case, when the calc hours function is called, the value associated with the variable temp is passed to the function and assigned to the parameter temperature. Great. We'll now follow a similar approach for the calculation of the calories burned. We first define the cal calories function, which takes the duration of the hike in hours and the difficulty of the terrain as inputs. Then we copy the calorie calculation code block into the function's body and write the corresponding return statement. Finally, we replace the second block of code with a call to the calc calories function. Note that the call to the calc calories function takes the output of the calc hours function as input. Therefore, we must call the calc hours function before calling the calc calories function. To complete the revision of our code, we create a third function called print results, which displays the output. This function takes the calculated hours and calories as inputs and prints those quantities in a user friendly format. Note that since the sole purpose of this function is to print the output, we do not need the function to return any value. Thus, we omit the return statement. Lastly, we replace the output code with the print results function call. Great. Now that we have refactored our code, let's run it to confirm that we still obtain the same outputs. And indeed we do. But with these changes, we have significantly improved the structure of our code. By breaking our programs logic into separate focused functions, we've achieved several benefits. Concision. The main programs body, excluding the function definitions is considerably shorter. Readability. Each function has a clear, singular responsibility that can be examined independently. Comprehension, the program's overall workflow is now more easily understood. Indeed, our new code structure clearly delineates the three primary tasks being performed, calculate hiking time, determine energy expenditure, and print the results. In contrast, distinguishing these tasks in the original version of the code required more efforts and careful reading. Pike implements the requested modifications to it forecasting functionality. To Jamie's satisfaction, it'll be able to provide more accurate duration and calorie estimates moving forward. In the last two videos, we explored situations where user defined function improved the quality and structure of our code. In the exercises that follow, you will practice two critical skills. First, identifying situations where user defined functions are helpful, and second, determining the scope and the responsibilities of the functions that you define. 47. User-defined Functions - Exercise Solutions: This workbook, you created several user defined functions to answer various financial questions. Then you use those functions to help solve financial problems for clients. Let's discuss the solutions. In Exercise one, we were asked to write a function that calculates the monthly loan payment given the parameters, loan amount, annual interest rate, and number of years to repay the loan. To do this, we use the three equations given to calculate the monthly interest rate, number of payments, and finally, the monthly payment amount. Note that the monthly interest rate and number of payments are used in the monthly payment equation, so they need to be calculated before we can determine the monthly payment. When we use the function to calculate the loan payment on a $10,000 loan at 5% annual interest rate over 30 years, we get a monthly loan payment of $536.82. In exercise two, we wrote a function that estimates a client's savings at retirement given the initial savings amount, annual contribution, annual rate of return, and number of years until retirement. Inside this function, we first create a new variable, total savings and set it equal to the initial savings. Next, we create a four loop that iterates over the years until retirement, incrementing the total savings variable by adding the yearly contribution and growing the investment at the annual rate. In the loop header, we create a range of numbers from zero up until the year's parameter. This range ensures that the loop iterates exactly once per year until the client retires. Additionally, we use a placeholder as the iteration variable, since we will not use this value within the body of the loop. Inside the loop body, we first increment total savings by the annual contribution amount. Then we grow the total savings by the rate of return over one year. Growing the retirement savings in this way means that we properly account for the compound growth of an investment over time. After the loop is finished running, we return the final total savings amount, which contains the value of the investor's savings at the time of retirement. Finally, we use the function to calculate the retirement savings of a client with a $10,000 initial investment who wishes to retire in 30 years. With an annual contribution of $5,000 and an expected rate of return of 5%, their retirement savings will amount to $392,023.37. Since we used keyword arguments, we could pass the values into the function in a different order than what the function specified. As a result, the function call is more readable, since we know what each value represents within the function. In exercise three, we wrote a function to project the growth of an investment given the investment amount, the number of years the investment will be allowed to grow, and the expected annual growth rate. In the header of the function, we made this annual growth rate optional by using a default parameter. Then we calculated the future value of the initial investment using the given equation. Finally, we return that value. When we call a function without an annual rate of return, it uses the default 7% rate. However, when we do specify a rate, the function uses that rate instead of the default 7%. In exercise four, we needed to write a function that performs a budget analysis given monthly income and a list of monthly expenses. First, the function calculates the total monthly expenses by summing the elements of the expenses list. Then it subtracts the total expenses from the monthly income to determine whether the client has a surplus to save or is running a deficit. The function returns two values, the savings or deficit amount and the total expenses. In this case, returning two values is appropriate because the values are closely related, and this function focuses on a single task. However, if you find yourself returning multiple values calculated in a function that performs multiple tasks, it's better to split that function into smaller single purpose functions. When we use this function to analyze a client's budget with $4,000 in monthly income and this set of expenses, it returns both a surplus amount of $1,550 and $2,450 in monthly expenses. In Exercise five, we wrote a function that analyzes an unspecified number of expense categories using arbitrary keyword arguments. Arbitrary keyword arguments allow the function caller to pass in as many keyword arguments into a function as they wish. Those keyword arguments are collected into a dictionary called expenses. This means that we can use dictionary methods like values and items to perform operations on the expenses dictionary. Inside the function, we first sum all of the values in the expenses dictionary to calculate the total expenses. Then we iterate over each key value pair, printing out the category name, amount, and the categories percentage of total expenses. Finally, we return the total expenses amount for use outside the function. When we call this function to analyze a client's list of rent, groceries, utilities, and entertainment expenses, we obtain this expense breakdown and total expenses of $950. Finally, in Exercise six, we use the functions we created to help some clients. In part A, we helped John perform a budget analysis. We passed his monthly income and list of monthly expenses into our analyzed budget function, which returned the surplus or deficit amount and the total monthly expenses. John has a monthly surplus of $3,750, as well as $6,000 of monthly income to cover his $2,250 of monthly expenses. Then in Part B, we re analyzed John's monthly budget after factoring in his potential mortgage payments. To do this, we first called our calculate loan payment function and passed in John's loan details as arguments. This function returns the monthly loan payment, and we output. Then we factored this mortgage payment into John's monthly expenses by appending it to the monthly expenses list. Next, we called our analyzed budget function with John's monthly income and updated monthly expenses. This function returns the amount of savings or deficit and John's total monthly expenses. John has a monthly mortgage payment of $432.25. And based on his income and expenses, he has $2,317.75 of monthly surplus. In Part C, we needed to help Maria calculate her retirement savings. To do this, we called our calculate retirement savings function, passing in her details as keyword arguments. Here, using keyword arguments allows us to pass in the arguments in any order we wish. Based on Maria's retirement details, we obtain that she will have $376,083.52 in savings at the time she retires. In part D, we helped Lisa track her expenses. We called our Analyze expenses function passing in each of Lisa's expense categories as arbitrary keyword arguments. We explicitly assigned a name to each argument, since these names will become the keys of the expenses dictionary within the function. This function then prints the expense category breakdown. Lastly, in part E, we helped Alex project the growth of his inheritance and analyzed his expenses and monthly budget. First, we called our project investment growth function to calculate that Alex's $10,000 inheritance will be worth $27,590.32 in 15 years at an annual growth rate of 7%. Second, we analyzed Alex's expenses by passing in each of his expense categories into our analyzed expenses function as arbitrary keyword arguments, just like we did in part D. Third, to analyze Alex's budget, we called our Analyzed budget function and passed in Alex's monthly income and the total expenses we obtained in the previous function call. Since the analyzed budget function expects a list of expenses, we converted the integer total expenses to a list. Finally, we displayed Alex's budget analysis. Awesome. Now you've practiced creating and calling user defined functions, along with learning several other key functions concepts. Next, we will dive into the topic of namespace and scope and get a little more practice with user defined functions. 48. Namespace and Scope: Now that we've had some practice writing our own user defined functions, let's revisit an issue that we briefly touched upon earlier. When we helped the architect calculate the area of a building using the rectangle area function, we noticed that the area variable could not be accessed from outside the function where it is defined. In this video, we'll explain why we got that error. To do so, we must explore two new programming concepts, name spaces and scope. These ideas build directly upon the notion of variable that we have studied before. So let's begin by briefly reviewing this notion. Let's begin with a basic program that calculates the area of a rectangle without using a function. This program first assigns values to several variables representing the length, width, and measurement units of the rectangle. Then it calculates the rectangle's area and prints the result with the proper unit. As you already know, when PyTon executes the first lines of this program, four variables are created and assigned values. However, there is more happening behind the scenes. When PyTon executes variable assignments, it adds the variable into a structure called the global namespace. You can think of a namespace as a labeled container that holds the names of variables and functions created during execution, allowing PyTon to manage and access them efficiently. In our rectangle area program, the global namespace act as the primary container, holding all the variables that we've created, length with unit and area. Variables stored in the global name space are accessible anywhere during a program's execution. This enables us to use them freely for calculations and output. In a simple program like this one, which does not use functions, it is sufficient to understand how the global namespace work. However, as programs grow more complex, we often organize our code into functions to improve readability and reusability. The introduction of user defined functions changes how variables are accessed and managed in a program. Let's see how by tracing the execution of this program, when the first line of code is executed, the variable unit is assigned the value feet. Because this assignment is performed within the main program, the variable unit is starred in the global namespace as before. In the following line of code, PTN encounters the definition of the rectangle area function. Upon execution, the function's name is stored in the global namespace. Since the rectangle area function is now part of the global namespace, this function, like the unit variable, can be accessed anywhere in the program for the remainder of the execution. A first function call follows the definition of the function. At the very beginning of this function call, PyTon assigns the value 100 and 140 to the land and width variables respectively. Okay. But where in the name space will PyTon store these two variables? This is where things get interesting. When variables are created within a function, PyTon does not store them inside the global namespace. No, instead, PTN creates a new namespace associated with the function called the functions local namespace. The functions local namespace is where the variables length and width are stored. As we'll shortly see, this separation of name spaces helps prevent naming conflicts and allows functions to have their own private variables. Once the arguments have been assigned, PTN calculates the area of the rectangle. Because Piton is currently executing the body of the function, the private variables length and width are accessible. The result of the calculation is then assigned to the variable area. Now, because the assignment is performed in the body of the rectangle area function, the variable area is also added to the functions local namespace, and not the global namespace. This becomes important later. When executing the final line of the function's body, PyTon prints the content of the variables area and unit. Recall that variables in the global namespace are accessible from everywhere in the program, including during the execution of a function call. Now that all the lines of code in the function have been executed, the program wraps up the execution of the function call by discarding the local name space along with its content and returns to the main program. At this point, the program's global name space only contains the variable unit and the function rectangle area. That's specifically why in the previous video, we obtained an error message when attempting to print the rectangles area from outside the function. As you can see, at this point in the code's execution, the variable area has been discarded, so we can't use it. When our program executes the second function call, Python repeats the same steps as before. First, a new local namespace is created. Next, the arguments are assigned to the corresponding variables. The calculation is performed and the output is printed. Finally, the local name space is again discarded. Awesome. Now that we have introduced the concept of name spaces, let's bring in some more terminology. Variables that are stored in the global name space are called global variables. Variables stored in a local name space are on the other hand, called local variables. Because global variables are accessible everywhere in a program, we say that they have a global scope. On the other hand, local variables are only accessible within the function in which they are defined. So we say that they have a local scope. The notions of namespaces and scope are admittedly more abstract than the other programming concepts we have covered so far in this course. In the next video, we'll try to make those notions more concrete by going through some examples. 49. Namespace and Scope - Guided Examples: At the end of day two of their five day hike, Jamie and Pike come across a small rectangular clearing in the forest. Jamie is considering setting up camp there, but she worries that there will not be enough free space to relax once they pitch their tent and build a campfire. Given the concern about space, Jamie asks Pike to determine if the clearing will provide the 40 square feet of free space they need. To answer Jamie's question in BTon, we first create a function that calculates the area of a rectangle given its length and width. We can then use this function to calculate the area of the clearing and the area of the tent. Next, we create another function that calculates the area of a circle given its radius. We then call this function to calculate the area of the campfire. Finally, from the clearing area we calculated, we subtract the tent area and the campfire area to get the amount of free space left and print the result. That's all good. But notice that we have used the variable name area to store the results of our calculations inside both functions. Can we really do that? Can the same variable name be used inside two different functions or could this create some sort of conflict during execution? Let's trace the program's execution to see if this creates an issue. When the first line of code is executed, PyTon reads the definition of the rectangle area function and adds the function's name to the global namespace. PyTon then reads the circle area function definition and also adds it to the global namespace. Following the definition of our two functions, BTN moves to the first rectangle area function call. As you already know, when the rectangle area function is called, PTN creates a local name space where the arguments ten and 12 are assigned to the parameters length and width respectively. Moreover, during the functions execution, Biton assigns the result of the area calculation to the variable area in the functions local name space. The function call concludes by returning the value of the variable area to the calling point. Since there is only one area variable in any of the name spaces, there is no possible confusion regarding which area variable should be returned. Once the return statement has been executed, all the variables in the rectangle area name space are destroyed and a new global variable clearing area is created to store the function's return value. On the execution of the next rectangle area function call, Biton creates a new rectangle area namespace that contains the function parameters. The area of the tent is then calculated and stored in a new area variable. Then Python returns the value of the area variable. Since there is once again, only one area variable in any of the name spaces, there is no possible confusion regarding which area variable should be returned. So far, so good. When the function returns, all of the variables in the rectangle area namespace are destroyed and a new global variable tent area is created to store the function's return value. Finally, Piton calls the circle area function to calculate the area of the campfire. Here, a new local name space for a circle area function is created with the perimeter radius. PyTon then calculates the area of the circle and assigns it to a new local variable area. When Pyton returns the calculated area at the end of the function's execution, there is once more, only one variable name area in any of the name spaces. As a result, there is no possible confusion regarding which value should be returned to the program. The bottom line here is this. When defining functions, we can reuse the same variable names without issues. Local variables live within their function name space and die when the execution completes. This guarantees that naming conflict will not occur when we use the same variable names in multiple functions. Note that this principle also applies to parameter names. We can reuse parameter names across multiple functions. In the exercises, we will verify that reusing parameter names will not cause issues in our code. For the time being, just take my word for it. Awesome. With that observation behind us, let's finish tracing the code. When the circle area function returns, its name space is destroyed, and the return value is stored in the global variable campfire area. Finally, using the three area variables, PyTon calculates the free space and prints the result. Great. If Jamie and Pike set up their tent and campfire in this clearing, they will have almost 49 square feet of free space, which is more than enough. While they set up cam to unwind after a hard day of hiking, we will work over time to deepen our understanding of variable name conflicts. As we just saw, different functions can use the same local variable names without problems because each function call creates its own namespace. However, we haven't discussed what happens when a global variable has the same name as a local variable. For example, let's rename the clearing area variable to area in the main program. That area exists as both a local and global variable, how will PyTn behave? To find out, let's trace the execution of our code. Like before, PyTN begins by reading the function definitions and storing the function names in the global namespace. Then it executes the first function call, creating the rectangle area, local namespace. Inside the rectangle area function, PyTon calculates the area and stores the calculation inside the local variable area the value of the area variable is then returned where the function was called. At this point, there is only one area variable in any of the name spaces, so there is no potential conflict. When the function returns, all of the variables in the rectangle area name space are destroyed, and a new global variable area is created to store the function's return value. Interesting, we now have a global variable named area. I bet you can see where things are going. On the execution of the next rectangle area function call, PyTon creates a new rectangle area namespace that contains the function parameters. PyTon then calculates the area and store the result of the calculation inside the local variable area. Let's pause here for a second to examine the name spaces. Two variables named area now exist in different name spaces, a local variable containing the tense area calculated in the current function call and a global variable containing the clearings area calculated in the previous function call. When asking PyTon to return the value of area at the end of the current function call, which of the two variables will PyTon return? Since the same variable name is used to reference two different values, PyTon needs a way to figure out which value should be returned. In the Pyton language, the rule is to use the local version of the variable when there is a potential conflict. In this example, it means that PyTon will return the local variable area created within the rectangle area function and not the global variable area we assign at the end of our previous function call. When the functions execution is completed, the local name space is discarded. Then PyTon calls the circle area function, and a new local namespace is created. During the functions execution, Piton calculates the campfire area and assigns the result to the local variable area. Here again, there are two area variables in the name space. One is local. The other one is global. As a result, Pyton returns the local version of the area variable at the end of the functions execution. When the function returns, all of the variables in the rectangle area name space are destroyed and the value of the local area variable is assigned to the Campfire area global variable. In the next line of code, Pyton uses the variable area to calculate the remaining free space. At that point, only the global version of the area variable exists, and there is no ambiguity. Finally, PTN prints the calculation result, which is identical to what we obtain in our first rundown of the code. Over the last two videos, you have seen how PTN manages name spaces as it executes code. Distinguishing between the global and local name spaces is critical when writing user defined functions. In the following exercise, you'll get to practice that skill. 50. Namespace and Scope - Exercise Solutions: This workbook, you trace through four different programs to determine their output. Let's break down each program to illustrate their namespaces and understand how the logic, variables and functions interact to produce the final output. In exercise one, we recall that if a variable isn't defined locally, Python will search the global namespace to find it. To understand this program's output, let's trace it and build the namespace step by step. First, Python reads the two variable assignments and the function definition, adding the names length, width, and calc wrecked area to the global namespace. Next, Python executes the Calc wrecked area function call, creating a local namespace. Within the function, the variable width is added to the local name space. When Python reaches the length times width calculation, it must determine which values to use. Bec a local width variable does exist, Python uses this one instead of the global width. However, since there is no local length variable, Python expands its search to the global namespace and finds it there. Remember, Python falls back to the global variable when no local option is available. As a result, the calculation uses length equals five, and width equals two, giving an area of ten. When the function returns, the local namespace is destroyed and ten is passed back to the call point and printed. In exercise two, we learned that function parameters act as local variables within their respective functions. Even if different functions use the same parameter names, it doesn't cause any issues because each function has its own independent local scope. To understand this program's output, let's trace it and build the namespace step by step. First, Python reads both function definitions and adds them to the global namespace. Next, Python executes the elk triangle area function call. This creates a local namespace for the function and adds the parameters base and height to it. During the calculation, only one base and one height variable exist in this local name space. Since there is no conflict with any other variable names, the area is calculated as one half times five times three, resulting in 7.5. After the function returns, the local namespace is destroyed, but the return value 7.5 is passed back to the main program and displayed. Then Python executes the Calc wret area function call, which also creates its own local namespace and adds the parameters base and height to it. As before, there is only one base and one height variable in the function's local scope. With no naming conflicts, the area is calculated as five times three resulting in 15. The value 15 is passed back to the main program and displayed, and the functions local name space is destroyed afterwards. In exercise three, we learned that when a perimeter and a global variable share the same name, Python will use the most local name within the current scope. Let's trace the program to understand the namespace in this case. First, Python reads the global unit variable and the elk square area function definition into the global namespace. Next, it executes the Calk square area function call, creating the function's local namespace and passing the values four and meters as arguments to the length and unit parameters respectively. The function then returns a string containing the squared length and the unit. At this point, there are two unit variables, one in the global namespace, and one in the functions local namespace. Since Python always uses the most local variable when there's a name in conflict, it selects the unit variable from the function's local scope, which has the value meters. As a result, when the function returns, the output is 16 meters. In Exercise four, we learned that conflicts can also arise when a global variable, a function parameter, and a local variable share the same name. In such cases, the most local name is still always used. Let's confirm this by tracing the program. As an exercise three, Python first reads the global unit variable and the elk square area function definition into the global namespace. Then it executes the Kelc square area function call, creating the functions local namespace and passing four and meters as arguments to the length and unit parameters. Inside the function, the unit variable is then reassigned to yards overriding the parameter value of meters. At this point, there's a naming conflict between the local unit variable and the global unit variable. However, as we learned in exercise three, Python always uses the most local version of a variable. In this case, since the local unit now holds the value yards, that value is used when constructing the return string. As a result, when the function returns, the output is 16 yards. Awesome. Now you have a solid understanding of how namespaces and scope work in Python. Now it's time to tackle the final core topic of this course modules and libraries. 51. Modules and Libraries: In previous lectures, we saw that when Bton's built in functions fall short for a given task, we can always achieve what we want by creating our own user defined functions. That's great. But writing our own functions is time consuming, and we can make mistakes. Thankfully, in many instances, there is another option. Indeed, PTN offers a vast ecosystems of modules and libraries, offering pre written and tested code that can perform a wide range of tasks. In this video, we'll learn how to integrate and use these powerful PTN libraries into our programs. We'll start slowly by introducing the libraries through an analogy. Imagine PyTn's built in function as the books on your personal bookshelf at home. These books, just like built in functions are instantly accessible but limited in number. When the book you need can't be found at home, you may be able to find it by visiting your municipal library. In our analogy, PyTon libraries act as the programming equivalent of municipal libraries. They expand the set of available functions when PTon's built in functions fall short. PTN offers a vast ecosystem of libraries, each serving different programming needs. Among them, the PyTN Standard Library stands out as one of the most important. So that's where we'll begin our exploration of libraries. Just as a municipal library is organized into sections, each grouping books of the same genre, the PyTN Standard Library is organized into modules, each grouping related functions. For instance, the Bton Standard Library has a math module that contains functions performing mathematical operations such as taking the square root or the logarithm of a number. The library also includes a random module, which provides functions for generating random numbers, which is useful for simulations and a statistics module, which provides functions for calculating common statistics like the mean and the median. However, just as the books at the municipal library require more effort to access than the ones you have at home, functions in the PTN standard library are not as readily available as PTNs built in functions. To use a function from a module of the standard library, we must first check out the function from the library by importing it into our program. For example, to import the square root function, SQRT, from the MAT module, we write from MAT Import square root. In that statement, the fra Mat part instructs Piton that we want to retrieve a function from the MT module. The import SQRT part specifies which function we want to import from that module. Once imported, we can use the square root function as many times as we need in our program, just like any built in function. Besides the square root function, the MT module contains many other helpful functions. For example, the PD function calculates the product of the elements in a list. This function could be helpful to calculate the cumulative growth rate of an economy over the last five years given a list of annual growth rate. Of course, using the Pd function is not necessary in this case. We could find the answer by using a four loop, iterating over the elements of the list to calculate the cumulative product of the growth rates. But why reinvent the wheel when importing the prod function is so simple? Besides the MT module, the PyTN Standard library contains many more useful modules, some of which you'll explore in the exercises. Unfortunately, we can't do justice to all the functions available in the PyTN Standard library in this course. There are simply too many. For that reason, on the Git up page of this course, there is a link to the PTN Standard Library documentation where you'll find a list of functions included in that module. Feel free to consult this resource whenever you need to find a specific function or explore the capabilities of a particular module in the PyTN Standard Library. However, as comprehensive as it is, the PTN Standard Library also has limits. Just as your municipal library doesn't contain all the books ever written, the PTN Standard Library does not include functions for every possible programming needs. Fortunately, there are other libraries called external libraries that can help in those situations. External libraries have been created by the PTN community to address specific programming needs ranging from data analysis and machine learning to web development, data visualization, and more. To gain access to these external libraries, you must first get a library card by installing them. In an interactive notebook environment like Google Colab, getting this library card can be done using PTNS preferred installer program, also known as PIP, to install an external library type exclamation point, PIP install, followed by the name of the library you want to install in a code cell. This line of code instructs PyTN to install the MTPltLib library, a popular tool for data visualization in PTN. It's worth noting that Google Colab comes pre equipped with many popular library cards. For instance, Matpltib is one of those pre installed libraries in Colab, as the requirement already satisfied output message indicates when we run the code. Re installing a pre installed library does no harm, but it is not necessary and it can be skipped. After installing a library, we can use the dot notation to import specific functions into our program. Here, we import the plot function from the PyPlot module in the MatplotLib library. We should know that when we imported the PD function from the MAT module of the PyTon Standard Library, we did not specify the library's name. The BTN Standard Library is the exception. For this library and this library alone, we do not need to specify the library's name before accessing its module. For all other libraries, including MatplotLib, we must specify the library name before accessing its modules. Once a function from an external library has been imported, it can be used in the program just like any other function. For example, let's say we have a list of numbers, X that we want to plot against some other list of number, y? This can be done with a call of the plot function, passing X and Y as arguments. Executing the cell, we get a graph of our data. Awesome. But at this stage, you may be wondering, how do I determine if there is an external library that can help me solve a given programming task? Since thousands of external libraries are currently out there and more are continuously being introduced, memorizing the list of available libraries is not the answer. Instead, the best way to determine if there's an external library that can help you is a Google search or a query to your favorite large language model like Chat GPT. Once you have identified a library that might be useful for your task, you should consult its documentation to find the specific module where the functions you're interested in are located. A Google search is generally all that's needed to find the documentation. In the exercises and the final project, you will explore some of PTN's most popular external libraries in detail and become familiar with this discovery process. To sum up, when PyTN's built in function and its standard library falls short, external libraries provide a large number of additional functionalities. However, to access these functionalities, we must first install the library containing the desired function and then import it into our PTN program. The vast collection of libraries available in PTN is one of the greatest strengths of the language. By leveraging the global knowledge of the PyTon community, user like you can stand on the shoulders of giant and tackle complex tasks with remarkable efficiency. But don't take my word for it. The best way to appreciate the power of PyTon libraries is to see them in action. In the next video, we'll explore together a few use cases. 52. Modules and Libraries - Guided Examples: Since we last caught up with Jamie and Pike, they have successfully completed their challenging five day hike. Back home, Jamie feels a sense of pride and accomplishment. She's eager to share her adventure with friends and family and decides that a visual representation of our daily progress would help tell the story. Although Pike isn't naturally skilled at drawing, he knows exactly where to find the right tools to create the figure that Jamie wants. Just as Pike needs to rely on external tools to draw a chart, we'll rely on external libraries to create a nice figure in PyTon. More specifically, we'll use the Matpltib library. As we mentioned in a previous video, the Matpltib library is already installed in Colab, so we can skip installation in this workbook. As we have seen, the plot function of the Pilot module can create figures, so let's import that function. We'll also import the show function to instruct PyTon to display the plot we create. While you can import the show function by writing a separate import statement like this, there is a more concise way to do it. Indeed, PTN allows us to import multiple functions from the same module by listing the functions to import after the import keyword. Awesome. Let's now create lists that contain the information we want to plot. The first list we create contains the days of the hike, and the second list contains the corresponding miles hiked on each of these days. Then we call the plot function with the days list as the X axis value and the Mils hiked list as the Y axis values. Finally, we instruct Bton to display the figure by calling the show function. Executing the cell, we obtain a plot of the miles hiked on each day. This is fine, but you will surely agree with me that this plot is pretty bare bones. In particular, there is no title, and the axes are not labeled. Let's fix this. To add a title and axis labels to a plot, we need to import the functions, title, X label, and Y label. Then we call each function passing the desired title or label as the argument. Neat. When we rerun our code, we obtain a graph with a descriptive title and properly labeled axis. But these are far from the only customization options we have available. For example, let's say that Jamie would like to plot a horizontal line on the graph to represent the average daily mile she hiked over the five days. This can be done in two steps using the axHline function. In the first step, we calculate the average daily miles hiked. In the second step, we pass the average as the argument of the AxHline function. After running our code, we obtain an updated plot in which the average daily miles are represented by a horizontal line. With this new line added to the graph, it is now easy to tell on which days Jamie hiked more than the average. And as a result, our graph is becoming more and more informative. Nevertheless, we have numerous additional options at our disposal to enhance the visual appeal and effectiveness of our graph. For example, by default, MTLtib represents data as a thin blue line without markers for individual data points. However, we can enhance the visibility of our data by specifying a marker style in the plot function. Passing the string, Oh, tells PyTon to add circular markers around the data points while maintaining the connecting lines between them. Running the code, we observe that datapoint markers have been added accordingly. That's great. Let's now make our graph more interesting by using different colors of lines and styles for each data series. For instance, let's say that we want our average mile line to be dashed and orange. This can be done using AxH lines, color and line style keyword arguments. Executing the cell updates our plot with the latest changes. Pretty right. As a final touch, we'll add a legend to our figure. To do that, we'll need the legend function. In my opinion, the most convenient way to use the legend function is to first create labels for each line in our graph. Then just call the legend function without any argument. By default, the legend function will use the provided labels to construct the legend. Wonderful. Now, that's a professional looking graph. As you can see, the Piplot module provides powerful data visualization functionalities. In fact, the Piplot module contains so many functions that importing them all one by one can be cumbersome. Fortunately, PyTon provides a more efficient approach. That is, we can import the entire module at once using the following syntax. Import Matplotlib dot Pilot. When we import the entire module this way, we can access the modules function by using the dot notation. As you can see, repeatedly typing the full module name can be conversome. Thus, to streamline our code, we often use aliases when importing entire modules. We create an alias by adding the keyword as followed by a short descriptive label after the import statement. For the Pipelot module, a common alias is PLT. Defining an alias this way allows us to use the shorter PLT instead of matplotlib dot PiePlt throughout our code. Awesome. Jamie is thrilled with the graph that Pike plotted. She posts it on social media and receives tons of likes. As we prepare to tackle the capstone project of this course, we'll bid farewell to Jamie and Pike for now. See you on the trails, Jamie and Pike. As you can see, Matpltlib is a powerful library. We'll explore it in greater details in the exercise workbooks. Besides Mat Plutlb, the exercise workbooks will also let you explore several other very useful PyTon libraries. 53. Python Standard Library - Exercise Solutions: This workbook, you explored the math random and statistics modules from the Python Standard Library. Let's go over the solutions. In exercise one, we investigated the math module. In part A, we were given a list of population densities and asked to calculate the square root of each value in the list. To do this, we apply the Math modules SQRT function and add ten to each element using either a four loop or a list comprehension. Both methods give us the protected area sizes calculated from the number of deer in each herd, but the list comprehension is more concise. In Part B, we were asked to calculate the growth rate of the frog population using the provided growth equation and inputs. To implement this equation in Python, we use the EXP and log functions from the math module. The EXP function calculates the natural exponential raising E to the power of its argument, while the log function computes the natural logarithm when called without specifying a different base as an argument. We compute the frog populations weekly growth rate to be 111.47%. In Part C, we were given a list of daily food requirements for several species and asked to calculate their total food needs over 120 day winter season. Crucially, before calculating the total intake over the hundred and 20 days, we needed to round each value up since the emergency food is only available in whole units. To do this, we apply the SEL function from the math module to each element in the daily food intake list using a list comprehension. Next, we multiply each rounded value by 120 days to get the total food required for the winter season. As you can see, failing to round up the daily intakes before multiplying leads to noticeably different totals. Alternatively, we can achieve the same outcome using a four loop instead of a list comprehension. In Exercise two, we used the statistics module to calculate the mean, median, and mode of the moose population counts given. The statistics module does all the heavy lifting for us by providing the mean median and mode functions. We just pass the population counts list to each of the functions and output the results. Lastly, in exercise three, we tackled the random module. In part A, we were asked to use the random modules uniform function to model the potential remaining lifespan of each rabbit we are tracking and calculate its total projected lifespan. We start by using a list comprehension with the uniform function, which generates a float between two specified values. In our example, given a rabbit that is 8-years-old today, our list comprehension will generate a random float 0-12 minus eight, which is four to model its remaining potential lifespan. Using the list comprehension, we generate projected lifespans for each rabbit in our rabbit ages list. Then to calculate the total lifespan for each rabbit, we use another list comprehension and the ZIP function. The ZIP function pairs each rabbit's age with its corresponding projected remaining lifespan. We add each rabbit's current age to its projected remaining lifespan to compute its total projected lifespan. Lastly, we use a four loop to output the results. In Part B, we were given the probabilities of several weather events and asked to model the growth of the rabbit population over the next 12 months to forecast its size one year from now. We used the random modules choices function for this. We pass in the population growth rates as the values to be randomly chosen from, the weather probabilities as the weights the function should use, and K equals 12, which tells the function to choose 12 random population growth rates. This call results in a list of 12 simulated population growth rates, one for each of the next 12 months. Then using a four loop, we apply these rates to the rabbit population cumulatively growing it over the next 12 months. Finally, we output the forecasted rabbit population for one year from now. In Part C, we enhanced our simulation to output multiple 12 month population forecasts at once. We embed our code from Part B into a four loop that runs ten times, appending the result of each simulation to the simulated Pops list. When the loop is done running, we output the list of ten simulated population forecasts. In Part D, we use the statistics module to analyze the list of ten population projections we generated in Part C. Specifically, we compute the mean standard deviation and quartiles of our data. Like an exercise two, the statistics module provides all the necessary functions, so we simply call the mean standard deviation and quantiles functions. By default, the quantiles function computes quartiles, but it also allows you to adjust the N parameter to divide the data into more sections if needed. Lastly, in part E, we used the random modules CD function to make our random values reproducible. The seed needs to be set before generating any random values. This ensures that all values produced by the choices function are random but can be reproduced in future runs. Setting a seed is commonly used for testing or debugging code that involves using random values. Great. As you have seen, the Python Standard Library is a powerful set of built in tools that can aid in solving many types of problems. But as we mentioned in previous videos, there are many other external libraries provided by the Python community that are available for us to use. In the next few videos, you will have the opportunity to explore several of these libraries. 54. Matplotlib - Exericse Solution: This workbook, you learned how to create several basic types of charts and graphs using the MatplotLib library's PyPlot module. Let's break down the solutions. In exercise one, we were given a list of sales data and used a line chart to visualize it. MatplotLib allows us to create a line chart by calling the plot function with a list of X coordinates here, the range of days and a list of Y coordinates, the sales data. Additionally, we can customize the line chart by specifying a color, marker style, line width, and marker size. Then we add a title, X label, and Y label by calling the appropriate functions. Finally, we add a grid and display the plot. In exercise two, we were given lists of categories and sales data and created a bar chart showing the sales breakdown of the three categories. To do this, we used the bar function and passed the goods categories as the X variable and the sales data as the Y variable. Additionally, we also passed in a list of colors to customize the charts bars and added a title and labels for the X and Y axis. Then to add the sales data amounts to the top of each bar, we used a four loop and matplot Libs text function. This function takes X and Y coordinates for the labels as the first two arguments, followed by the text to display and the horizontal alignment. Finally, we display the chart. In exercise three, we were given the percentage of customers in different age groups and generated a pie chart to visualize the data. We created a pie chart using Matplotlibs Pi function, passing in the list of percentages as the data and the age groups list as the labels. Additionally, the Pi function takes the slice percentage label format and list containing wedge colors as keyword arguments. Next, we add a title and legend to our chart. The legend function takes the data to display as arbitrary arguments and other formatting features like the title and location as arbitrary keyword arguments. Lastly, we display the chart with the show function. Finally, in exercise four, we were given data about advertising spend and resulting sales and created a scatter plot to visualize the relationship between the two variables. To do this, we called the scatter function passing in the advertising spend and sales data. We customized the color and size of our scattered dots with two additional arguments and added a Title X and Y labels to the plot. Lastly, we displayed the plot with the show function. Great. You now have experience creating line, bar, and pie charts, as well as scatter plots using MTPotib. However, we've only just begun to explore its potential. Matplotlib is an essential tool for data visualization in Python, and I encourage you to continue exploring its features to enhance your problem solving capabilities in the future. 55. Pandas - Exercise Solution: This workbook, you explored the Pandas library to analyze and manipulate flight data. Let's discuss the solutions. In Exercise one, Part A, we loaded the given flight data into a data frame. To do this, we simply passed our data into the dataframe function. Then when we output our data, it is displayed as a well formatted data frame. In Part B, we needed to display the first two flights in our flight info data frame. DataFrames have a method called head, which takes an integer number of rows to display as an argument. The output of this method call with the argument two is the first two rows of our flight info data frame. In Part C, we needed to generate summary statistics about our flight info data frame. DataFrames provide a method called describe, which calculates several useful statistics such as mean and standard deviation. Moving to exercise two, we learned how to filter our data frame based on certain conditions. In Part A, we created a data frame containing only flights traveling to LAX. To do this, we first used a conditional expression that identified which values in the destination column of our data frame were equal to LAX. This created a series of Booleans which we use to filter our data frame. The resulting data frame contains only the flights destined for LAX. In Part B, we filtered our flight info data frame to display only flights with an arrival delay greater than 20 minutes. As in Part A, we specified an expression to filter out the flights with arrival delays that are less than or equal to 20 minutes. The resulting data frame contains only flights with delays longer than 20 minutes. In exercise three, we performed calculations using data frame columns. In part A, we added a new total delay column to track the total arrival and departure delays for each flight. To create this column, we summed the values in the departure delay and arrival delay columns and told Python to store that data in a new column called total Delay. Displaying the updated data frame, we see that our new total delay column was added. In Part B, we calculated the total average delay across all flights. Since we already calculated the total delay column in Part A, we simply call the Panda's mean method on the total delay column. The result tells us that the average total delay is 35 minutes across all flights. In Part C, we calculated the average total delay for flights going to ORD. To do this, we first filtered the flight info data frame like we did in exercise two. Then we apply the mean method to the total delay column of the data frame containing the flights destined for ORD. We find the average delay for flights to RD is 46.25 minutes. Lastly, in Exercise four, we learned how to sort data frames. In part A, we sorted the flight info data frame by total delay in descending order. Pandas provides the sort values method into which we pass the column to sort by and whether the order should be ascending or descending. This method call produces a data frame where the flights are sorted by total delay in descending order. Finally, in Part B, we sort our flight info data frame by departure delay in ascending order. Like in Part A, we use the sort values method and specify the column to sort by and ascending order. This method call outputs a data frame where the flights are sorted by departure delay in ascending order. Awesome. Pandas is a powerful Python library for data manipulation and analysis, providing flexible data structures like data frames to efficiently handle structured data. You can use it in your own projects to simplify data cleaning, transformation, and visualization, as well as wrangling large datasets and performing analytics. 56. Language Translator App - Project Introduction: Grats. After lots of hard work, you've made it to the course project. Your task now is to build a language translation application that can translate text between various languages and manage a collection of favorite translations. You will need to use concepts like while loops, libraries, dictionaries, conditionals, and more. In this project module, you will find detailed text instructions that guide you through building your application. Additionally, we have provided the text of a sample interaction with the program to give you a better idea of how the menus and functionalities work. In the remainder of this video, I'll do a quick demo of how the final application will work. When a user launches your application, they are presented with a menu of translation options. Option one is Quick Translate. This option translates a word that the user inputs using the default from and to languages. Option two is print available languages. This displays a list of all available languages in the translator library, which you must install. Option three is change default languages. This feature allows the user to set default languages for translation, specifying both the source and target languages for future use. The initial default languages are set to English and Spanish, but users can choose any languages they prefer. Option four is translate and detect source language. Here, the user only needs to specify the target language and enter a phrase. The application will automatically detect the source language and translate the phrase accordingly. Option five is translate and specify languages. This option prompts the user to select both the source and target languages before entering a phrase to translate. And finally, option six is managed favorites. This takes the user to a sub menu where they can manage a dictionary of their favorite translations. If we choose option one, the application uses the default source language, English, and the default target language, Spanish to translate the phrase we enter. If we choose option two, the application lists all of the languages available through the Google Translator module. Each language is accompanied by an abbreviation that can be used in place of the full language name. Next, let's select Option four and enter the target language along with the word to translate. The application will automatically detect the source language and perform the translation. Finally, if we choose option six, we enter a sub menu for managing favorite translations where four additional options are available. Choosing Option one will allow us to add a favorite. We can enter the favorite phrase along with the source and target languages. Then this information will be saved to the favorites dictionary. Users can add as many favorites as they like. Using option four, we can view our favorites dictionary. Here, we see that all of the translations have been saved along with their source and target languages. If we wish to return to the translator options, we enter zero. And we can quit the program altogether by entering zero again. Great. Now it's time for you to start the project. Remember, detailed step by step instructions are available in this module as well as a sample interaction. Good luck and happy programming. 57. Language Translator App - Project Solution: Welcome to the Language Translators Solutions video. If you're here because you're feeling stuck on a step, don't worry. We'll walk through the solution one step at a time. You can follow along until you reach the part that's giving you trouble. And if you're here because you've already finished the project, congrats. You've put in a lot of hard work. So now let's dive in and check your answers. In step one, we start by initializing the project. The first thing we need to do is make a copy of the provided notebook. Next, we install the Deep Translator library by simply running the command PIP install Deep Translator. In step A, we write the display main menu function, which takes the default from and to languages as arguments. The print statements display the program's main menu. In step two B, we define two global variables, default from and default two. These will be used for the quick translation feature. The default from variable sets the source language while the default two variable sets the default target language. In step two C, we update the main program to call the display main menu function passing the global variables we defined in step two B as arguments. In step three A, we request the user's translator option choice with a call to the input function. In step three B, we create a conditional block, which will decide which action to take based on the user's input. Eventually, we will replace each print statement with the action's corresponding function call. But for now, we will use print statements as placeholders. If a user selects an option that doesn't exist, we display an error message. In step four A, we define the global variable that we use to control the main program loop. Then in step four B, we create the main program loop. To allow the user to make as many translations as they want, we use a wile loop controlled by the global variable we set earlier. We then move the code that displays the main menu, captures the user's choice, and determines the appropriate action inside of the while loop. Finally, we remove the print statement for option zero and instead set the should continue variable to false. Now, when the user enters zero, the program will exit. In step five A, we write the translate function. This function will take three parameters, the source language, the target language, and the text to translate. Inside the function, we use the Google Translator module and its translate method to handle this translation. Now, it might seem a bit strange to call a method like translate on what looks like to be a function, but that's because Google Translate is actually creating an object. The concept of an object is an object oriented programming notion that we haven't covered in this course. But don't worry. Understanding object oriented programming isn't necessary for using the library for simple translations like we're doing here. We simply return the result of the translate method which contains the translated text. In step five B, we write the function called quick Translate. The function takes the source and target languages as parameters and then prompts the user to enter the text they wish to translate. To perform the translation, we call the translate function created earlier, passing in the source language, target language, and the user's text as arguments. Finally, we capture the translated text that's returned by the translate function and display it. In step five C, we update the main program's conditional block to call the quick Translate function when the user selects option one. We pass in the default from and to language variables as arguments. So the only input the user needs to provide for this option is the text they want to translate. In step six A, we write a function to print the available languages in the Google Translator module. This function doesn't take any parameters. Inside the function, we call the G supported languages method and request the results to be returned as a dictionary. Then we loop through the dictionary, printing each language along with its corresponding abbreviation. In step six B, we update the conditional block in the main program to call the print available languages function when option two is selected. In step seven A, we write a function to set the default languages that the program will use during the quick translate feature. This function doesn't take any parameters. Inside the function, we prompt the user to enter a new default source language and then a new default target language. After that, we print a confirmation message letting the user know that the languages were successfully updated. Finally, we return both the from and to languages. In step seven B, we update the conditional block in the main program to call the set default Languages function. Since this function returns the new source and target languages as a tuple, we unpack these values directly into the global default language variables. In step eight A, we write the translate detect source lang function, which translates a phrase into a specified target language while automatically detecting the source language. This function doesn't take any parameters. Inside the function, we prompt the user to enter the target language. Then we call the quick translate function that we defined earlier to handle the translation. To automatically detect the source language, we pass the string auto as the first argument. The user provided target language is passed as the second argument. Since the quick translate function both prompts the user for input and outputs the translated text, we don't need to duplicate these actions in this function. In step eight B, we update the conditional block in the main program to call the translate detect source language function. In step nine A, we write the final translation function, translate specify angs. This function requires the user to specify both the source and target languages. Once those are provided, it calls the quick Translate function, which prompts the user for the text to translate and then performs the translation. In step nine B, we update the conditional block in the main program to call the Translate specify Lang's function. In step ten A, we write the function to display the favorites menu. This function doesn't take any inputs and simply displays the menu to the user. In step ten B, we write the function that manages the favorites dictionary. This function takes the favorites dictionary as an input. Inside the function, we define a new loop control variable to manage a wile loop, allowing the users to interact with the favorite's menu as many times as they like. Within the loop, we display the favorites menu and prompt the user to choose an option. Since we have not yet written these functions, we use print statements as placeholders. If the user enters zero, we set the loop control variable to false, which exits the favorites management loop and returns to the main program menu. In step ten C, we start by defining a new global variable to store the favors dictionary. Making the favorites dictionary a global variable ensures that it won't reset each time the user accesses the favorites menu. We also update the main program's conditional block to call the managed favorites function passing in the Global Favorites dictionary. Finally, we update the Global Favorites dictionary with the managed favorite functions return value. In step 11 A, we write the add favorites function. First, this function will prompt the user to enter the text they wish to favorite. Next, we ask the user to input the source language of the original text followed by the target language that they wish to translate it into. Then we call the translate function defined in step five A to handle the translation, passing in the user's text, source language, and target language as arguments. The translation result is captured in the translation variable. We then create a new entry in the Favorites dictionary using the text to favorite as the key, and a dictionary containing the source language, target language, and translated text as the value. Finally, we output a confirmation message letting the user know that their favorite has been successfully added to the dictionary and return the dictionary. In step 11 B, we update the conditional block in the manage favorites function to execute the add favorite's functionality if the user chooses option one. We also update the favorites dictionary with the return value of the function call. In step 12 A, we write the remove favorite function, which takes the favorites dictionary as a parameter. First, the function prompts the user to enter the favorite they wish to remove. Next, we check if the user's input exists in the favorites dictionary. If it does, we remove the entry and print a confirmation message. If the input does not exist, we display an error message instead. Finally, we return the Favorites dictionary. In step 12 B, we update the conditional block in the managed favorites function to execute the remove favorite functionality if the user chooses option two. In Step 13 A, we write the edit favorite function. First, the function prompts the user to input the favorite they want to edit. Next, it checks if the favorite exists in the dictionary. If it does, the user is asked for a new target language to translate the favorite into. Then we call the translate function passing in the original source language, the new target language, and the text to translate. This returns the original phrase translated into the new language. We update the favorites dictionary with the new target language and the updated translation followed by printing a confirmation message. If the user entered a favorite that doesn't exist, we display an error message. Finally, we return the favorites dictionary. In step 13 B, we update the conditional block in the manage favorites function to execute the edit favorite functionality if the user chooses option three. In step 14 A, we write a function to print the current favorites dictionary. First, the function checks if there are any entries in the dictionary. If there are, we use a four loop to iterate over all the keys and values in the dictionary, printing them in a clear and well formatted string. If the dictionary is empty, we simply display an error message. In step 14 B, we update the conditional block in the managed favorites function to execute the print favorite's functionality if the user chooses option four. Finally, in Step 15, we make our program more robust by handling errors that may occur from invalid user input. We start by modifying the main loop of our program. When we prompt the user for input, we wrap the code that casts the input into an integer inside a triblock. If the user enters non numeric text and the cast fails, we catch the resulting value error in the except block where we display an informative error message to the user. We also use the continue keyword to skip the rest of the current iteration and start the next one, ensuring the program doesn't crash. If the cast is successful, the usblock executes and the final formatted string is printed. We apply the same error handling approach to the managed favorites functions loop. Here, we wrap the user input cast inside a Triblock. If the cast fails, we catch the error in the accept block, display an error message, and move to the next iteration. If it succeeds, the se block executes as expected. Great. You've now seen how to build a language translation app using the Deep Translator library, complete with features like quick translations, customizable default languages, and error handling. Feel free to refine the app further and make it your own. Keep exploring and building. There's always more to learn.