Programming Foundations for Absolute Beginners: Learn Python from Zero to Hero | Karoly Nyisztor | Skillshare

Playback Speed


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

Programming Foundations for Absolute Beginners: Learn Python from Zero to Hero

teacher avatar Karoly Nyisztor, Senior Software Engineer, Instructor

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

66 Lessons (3h 43m)
    • 1. 1.1 How to Use this Course?

      1:29
    • 2. 1.2 What's Coding?

      2:57
    • 3. 1.3 Programming Languages

      2:22
    • 4. 2.1 Why Python?

      2:04
    • 5. 2.2 Setting up Python

      2:16
    • 6. 2.3 The Python Command Line

      2:37
    • 7. 2.4 Installing and Configuring Visual Studio Code

      2:32
    • 8. 3.1 Woo-hoo! Your First Python Program!

      4:35
    • 9. 3.2 Asking for User Input

      3:14
    • 10. 3.3 Using Comments in Code

      2:36
    • 11. 3.4 Declaring Variables

      5:32
    • 12. 3.5 Working with Numbers

      3:23
    • 13. 3.6 Using Basic Arithmetic Operations

      4:49
    • 14. 3.7 Working with Strings

      6:41
    • 15. 3.8 The Boolean Data Type

      2:15
    • 16. 4.1 Introducing Conditional Code

      2:42
    • 17. 4.2 Code Blocks

      2:00
    • 18. 4.3 Comparison Operators

      5:04
    • 19. 4.4 Going Deeper: else-if

      2:53
    • 20. 4.5 Nested Conditionals

      1:01
    • 21. 4.6 Using Logical Operators

      5:09
    • 22. 5.1 Why Do We Need Functions?

      3:13
    • 23. 5.2 Writing Functions

      3:33
    • 24. 5.3 Calling Functions

      2:40
    • 25. 5.4 Defining Function Parameter and Return Type

      2:57
    • 26. 5.5 Understanding the Scope of Variables

      4:28
    • 27. 5.6 Demo: Implementing an Area Calculator

      2:05
    • 28. 5.7 Testing the Application

      5:05
    • 29. 5.8 Enhancing the Area Calculator App

      4:33
    • 30. 5.9 Challenge: Calculate Rhombus Area

      0:59
    • 31. 5.10 Solution: Calculate Rhombus Area

      2:19
    • 32. 6.1 What's Iteration in Programming?

      5:11
    • 33. 6.2 Introducing the while Statement

      3:46
    • 34. 6.3 Avoiding Infinite Loops

      4:35
    • 35. 6.4 Writing for-in Loops

      3:09
    • 36. 6.5 Deeper into Loop Control Statements

      3:35
    • 37. 6.6 Rewriting the Login App Using the for Loop

      3:22
    • 38. 7.1 Storing Multiple Values

      1:48
    • 39. 7.2 Creating Lists

      3:41
    • 40. 7.3 Accessing List Items

      4:12
    • 41. 7.4 Modifying the Contents of a List

      6:03
    • 42. 7.5 Working with Tuples

      2:52
    • 43. 7.6 Storing Key-Value Pairs: the Dictionary

      2:53
    • 44. 7.7 Modifying the Dictionary

      3:15
    • 45. 7.8 Iterating through Containers

      4:20
    • 46. 7.9 Iterating through Containers Part 2

      2:44
    • 47. 7.10 Demo: Extracting Duplicates

      5:17
    • 48. 8.1 Getting Ready for Errors

      3:15
    • 49. 8.2 The Buggy Equation Solver

      3:37
    • 50. 8.3 Handling Errors

      4:00
    • 51. 8.4 Raising Exceptions

      2:53
    • 52. 8.5 Cleaning Up: the finally Keyword

      1:29
    • 53. 9.1 Working with Files

      2:11
    • 54. 9.2 Writing Text to a File

      5:50
    • 55. 9.3 Reading Text from a File

      3:37
    • 56. 10.1 What's Object Orientation?

      3:42
    • 57. 10.2 Understanding Objects

      3:38
    • 58. 10.3 Introducing the Class

      5:43
    • 59. 10.4 Abstraction

      1:24
    • 60. 10.5 Encapsulation and Data Hiding

      4:02
    • 61. 10.6 Inheritance

      3:56
    • 62. 10.7 Method Overriding

      2:11
    • 63. 10.8 Polymorphism

      1:33
    • 64. 11.1 The Importance of Algorithms

      1:35
    • 65. 11.2 The Problem with Naive Implementations

      4:30
    • 66. 11.3 Applying a 2000-year-old Formula

      3:30
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

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.

64

Students

--

Projects

About This Class

Learn the basics of programming through easy-to-follow, live Python coding examples.

We start by introducing the basic syntax of Python. The concepts presented in this section will make it easier for you to learn other programming languages, too.

Next, you'll learn how to write code that only runs if specific conditions are true. 

We then delve into the basic building blocks of reusable code.

The following module deals with loops-a fundamental programming concept that lets us perform a task multiple times.

You've learned how to work with individual pieces of data, such as a single number, a string, or a Boolean. In the next module, you'll learn about data types that can hold multiple values.

Even experienced programmers make mistakes. I dedicated an entire chapter to dealing with errors.

Then, you'll learn how to work with files using Python.

I'll also teach you the basics of object-orientation, the programming paradigm used to write all modern software applications.

Finally, you'll learn about algorithms that will make your code better and faster.

Topics include:
    – Basic Syntax
    – Control Flow
    – Functions
    – Loops
    – Containers
    – Error Handling
    – File Input and Output
    – Introduction to Object-Oriented Programming
    – Introduction to Algorithms

Meet Your Teacher

Teacher Profile Image

Karoly Nyisztor

Senior Software Engineer, Instructor

Teacher

My passion is helping people through online courses. So far, I've inspired over 50,000 students worldwide.

Hi there, my name is Károly Nyisztor. I'm a software engineer, online instructor, and book author. You can find my courses and books on all major platforms including Udemy, LinkedIn Learning, Lynda and Pluralsight.

I've worked with companies such as Apple, Siemens, SAP, Zen Studios, and many more. 
I've designed and built several enterprise frameworks, and I hold twelve patents related to inventions in the field of mobile computing.

I've developed over a dozen iOS apps and games- Libra Balance, My Travel Assistant, Travel Mate, iSyslog, GiftShopper, Zombie Run, to name a few.
Most of these apps have been featured by Apple(New a... See full profile

Class Ratings

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

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

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. 1.1 How to Use this Course?: If you're new to programming, you should watch it this course from start to finish. The class follows a linear path. Therefore, I'd suggest you go through every section as skipping any parts of this material may make other parts of the course difficult to understand. Here's a brief roadmap of what's covered in the upcoming chapters. We start by clarifying some fundamental programming related concepts. Then I'll give you instructions to set up the development environment required to follow and implement the coding examples. In the following chapters, we're going to delve into programming. We start with the basics and gradually build up the knowledge required to understand more advanced programming concepts. Throughout this course, I'll be using Python code examples. These examples are straightforward and I explain everything thoroughly. Entering the code and running it yourself is the most efficient way to learn the presented concepts. You may make some mistakes as you type the code, but don't worry. The more you practice coding, the easier it becomes. And let me share a little secret with you. Even seasoned developers make mistakes. To her is human, but to really foul things up, you need a computer. All right. Let's dig in! 2. 1.2 What's Coding?: Coding or programming is telling the computer what to do. It works by typing commands in a specific order. Every computer program consists of sequences of commands. Your mail app, the web browser, Facebook, WhatsApp, the games on your phone. Each of them is a set of instructions. These instructions tell the computer to perform specific tasks, like multiplying two numbers, opening a file or making your computer beep. Some programs consists of only a few instructions, while more complex ones may contain hundreds of thousands or even millions of instructions. To understand how programming works, let's imagine that you want to cook on omelette. You've never cooked before. So what do you do? You start by searching for how to cook an omelette on the Internet. Then you pick a website or a video that provides step-by-step instructions for cooking your meal. That's precisely how computer programs work. Programmers break down complex tasks into simple individual steps. The order of these steps is critical. Just like in the case of a recipe, you'll get completely different results if you mix up the instructions, let's assume that we can use the following instructions to navigate on a map. Move forward, turn left, and turn right. Next, we build a two sequences using these commands. First sequence, move forward, turn left, move forward, turn right, move forward. Second sequence, turn right, move forward, move forward, turn left, move forward. As you can see, the order of commands does indeed make a huge difference. The computer does what you tell it to do, even if the instructions do not make sense. For example, you could create the following sequence of commands and the machine would blindly execute them. Move forward, move forward, move forward. Programming mistakes may cause crashes, data corruption, performance issues, or even hardware failures. A programmer needs to know what instructions to use to achieve a particular functionality. What are the implications of using specific features or resources and how to detect and fix software bugs. 3. 1.3 Programming Languages: By now you've probably got an idea of what programming is. Giving directions to computers in the form of sequences of instructions. We provide these instructions using programming languages. When we say programming language, we usually refer to high-level programming languages like Python, Swift, C plus, plus, Java, or C Sharp. Each programming language consists of a set of keywords and some rules for instructing the computer what to do. It's like the vocabulary and grammatical rules. In the case of human languages, the following code snippets look differently. Yet they both convert from Fahrenheit to Celsius degrees. The first is a simpler basic program, and this one is Python code. Don't worry about the syntax for now. I just wanted to show you that we can use two completely different programming languages to implement the same functionality. How is that even possible? Does the computer understands so many programming languages? The short answer is no. The computer, or rather its CPU, the central processing unit, can only execute machine language instructions. The machine code isn't something you want to use to write programs. You'd need to enter numbers instead of humanly readable instructions. Forget statements like print or format, because the CPU only understand numbers. Besides the machine code is hardware specific. Machine language instructions that work on a CPU won't work on another model. Therefore, we need to use machine instructions that can be understood by each hardware we're targeting. Scary, right? But no worries. That's why high-level programming languages exist. When we execute our high level code, it goes through a series of transformations and eventually the machine code gets generated. At this point, our program can run on the computer. Nowadays, developers don't need to look into machine code. Just make sure that your code makes sense and it has no flaws. The rest is taken care of by smart developer tools. 4. 2.1 Why Python?: The biggest challenge when creating this course was choosing a programming language. My first thought was to pick swift. Swift is a modern programming language and it has a straightforward syntax. The code written in Swift is easy to read and it's perfect for beginners given all the tools APA provide. Besides it's open source. So why did I pick another programming language? The main reason is this. Swift is native to Apple. Therefore, it's perfect for those who own a Mac. You can even use it on Linux. However, there is no proper way to compile swift on Windows yet. I also consider Java. Java has been around since 1995, but it's still trendy. The TOB programming community Index ranked Java as the most popular programming language at the time of creating this course. Java is a cross-platform interpreted language. It was designed to run with the help of a Java virtual machine on any platform. That is, you could start programming in Java regardless if you are on a Mac, Linux, or a Windows system. Eventually, I decided to use Python. Here's why python is easy to pick up and you can learn the basics of programming quickly. Let's have a look at an example of written in Java. And here's the same code implemented using Python. Now, which version feels more natural? Python is one of the easiest programming languages out there. Python is a high-level programming language that has gained massive popularity among data scientists, ai and machine learning researchers who want to get their job done quickly. I'm confident that Python will have fast-track your journey into the world of programming. 5. 2.2 Setting up Python: Setting up Python on your computer. Let's begin by checking if Python three is installed and properly configured on your computer. I'll be using Python 3 in this course. So I recommend you install it to. If you're using Mac OS or Linux, you've probably got Python already installed on your system. You can check if you have Python 3 on your computer by opening a terminal window. On Windows, start the program called CMD. If you're on a Mac or a Linux system, launch the terminal program, you should get a window with a command line prompt. Next, type the following command in the terminal. Python 3, whitespace minus, minus version. As you can see, I have the right version on my Mac. If you get some error message in the console, tried typing Python whitespace minus, minus version. If you still get an error, that means that Python is not installed on your system. I'll show you how to install Python 3 in a moment. Now, if you're a Mac user, then the chances are that you have the original 27 series of Python. To that seven is the original order version of Python. Although it's still getting bug fixes, it's not actively developed anymore. So if you don't have Python 3 on your computer, you should install it from the official website. Visit the python.org website in your favorite browser. Hover your mouse over the Downloads menu. The link in the drop-down defaults to the version of your operating system, but you can also select your platform manually. Download the latest version of the Python 3 release. After the download is ready, launch it the installer and follow the instructions to complete your Python installation. Check if your installation succeeded by running the following command in the terminal. Python three, whitespace minus-minus version. Next, we're going to install and configure our development environment. 6. 2.3 The Python Command Line: Now that you have Python 3 installed on your machine, let's try it out. If you're on Windows, started a program called CMD on a Mac or a Linux system. Launch the terminal program. Next, type the following command in the terminal, Python 3. This command starts the interactive Python language shell, also known as read evaluate print loop. In short, grapple. A read evaluate print loop, also termed an interactive top-level or language shell, is a simple interactive computer programming environment that takes single user inputs. That is, single expressions, evaluates them, and returns the result to the user. A program written in a rapid environment is executed piecewise. The Python shell executes the Python instructions. We write. It reads the input entered by users. The value is the code we typed and print the results so we can see the response. Then it loops back to the first step. Now, let's do some basic math. We can add two or more numbers. Let's try for example, to plus two or two plus three plus five. We can also subtract numbers 120 minus 3.14, or multiply them. 17 times 6, divide 64 divided by eight, or 129 divided by 98. We can even raise a number to a power 5 squared, which should be 25. Write. The Python shell can also evaluate multiple operations. Python follows the order of operations when evaluating math expressions, we can create the shell anytime by typing exit. We talk about the parenthesis stuff later in the course. Now we're back to our command line. What if I'd like to go back and work a bit on my code, if I open a new REPL, it will start everything from scratch. There is no way to go back and continue where we left off. Ripple can be used to try out simplest snippets of code. However, it's not the right solution. If we want to edit or reuse our code. 7. 2.4 Installing and Configuring Visual Studio Code: The interactive Python language, the rapper, can be used to quickly type and try out a couple of lines of code. However, there are a lot of things that the Python shell can do for you. For example, you can go back to the previous line. If you want to change something quickly. There is no code completion or syntax highlighting and you can save your session to a file. Code completion is a feature that speeds up the process of writing code. As we start typing the code, the code completion engine comes up with a list of potential candidates. Besides speeding up software development, Goal completion reduces the number of mistakes and typos. And we have to memorize fewer keywords, function names, and so on. Syntax highlighting improves the readability of our code by using different colors and fonts to highlight categories of terms. This in turn reduces the time required to figure out what the source code does. Code completion and syntax highlighting are available in text editors and integrated development environments, also known as IDs. A code editor is a code centric text editor that provides syntax highlighting and conceive or open source files, but it won't execute your code lines. For example, Adam is such a code editor. Ides are more powerful in that they let you execute and test the code you've wrote. There are many ideas that can work with Python. In this course, I'll be using Visual Studio Code. It's a versatile IDE that's available for Windows, Mac OS, and Linux. You can download the latest stable version for free from code dot Visual Studio.com. Visual Studio Code comes with a variety of useful plugins that will make our life easier when working with Python. After downloading VS Code, launch it and go to the extensions panel. You can do that by clicking the View menu and choosing extensions or by clicking the extensions icon in the extensions panel, type Python in the search box and installed the one provided by Microsoft. This plugin comes with Python syntax highlighting, but it also lets us run and debug Python code from within the editor, installed the plugin and restart VS Code. Congrats. Now you're ready to start coding in Visual Studio Code. 8. 3.1 Woo-hoo! Your First Python Program!: In this lecture, you're going to write your first program in Python. We'll be using Visual Studio Code from now on. So if you haven't installed it yet, follow the instructions from the install and configure Visual Studio Code lecture. Also, make sure that you have Python version three setup on your computer as described in the video, setup Python on your computer. Let's start by opening VS code. We're going to create a new file. By clicking File and select new file. A new file gets created with the name Untitled one. Have a look at the status bar at the bottom. The status bar is enabled by default, but if you can't see it, go to View appearance and select Show Status Bar. The status bar tells us that the newly created file can hold plain text. We'll change that in a moment. But first, type the following in the editor window. Print. Hello, World. Now click file again and choose Save As name your file first program dot p-y, and save it. The PY extension here denotes a python source file. You should name all your Python source files according to this pattern. Xyz dot p-y, where XYZ should provide a concise description of what the code does. After saving the file, right-click in the editor area and select Run Python file in terminal. Visual Studio Code adds a new panel below the editor, and you should see the text Hello World displayed in the terminal. Print. Here is a built-in function that lets us output texts to the console. We must write it all lowercase. Otherwise, it wouldn't be recognized as a valid function name. Let's change the print to print with a capital P and see what happens if I try to run the file again. As expected, we've got a name error. I undo the change to get rid of the error. Now, let's talk a bit about the print function. An opening parentheses follows the function name print. Then between double quotes we provide the text to be output, Hello World. And we end the statement with the closing parenthesis. We must surround the text to be printed with quotes. You can also use single quotes. Python won't complain. Thus, both of the following statements will work. You need to be consistent. Either use single quotes or double quotes for strings. Don't start with a double quote and end with a single quote or vice versa. Otherwise, you will trigger a syntax error as in the following example. Now I remove this faulty line and let's print something else. Print. Hey Steve, feel free to use other names. Actually, you can print anything you'd like. Just make sure it's surrounded with quotes. Also, start each of your print statements on a new line. Use triple quotation marks to delimit your text if it must spend on multiple lines, the following statement will appear as it is in the terminal. Finally, don't forget to save your changes by clicking File Save or use the shortcut Command S on the Mac or Control S on Windows. You can run your program whenever you wish by right-clicking in the editor area and selecting Run Python file in terminal. Congrats, you just implement it and successfully ran your very first Python program. You made the computer print various texts. Next, we're going to write a program that waits for user input. 9. 3.2 Asking for User Input: Computers can perform all sorts of calculations blazingly fast and output the results in some form, typically by displaying them on the screen. That wouldn't be very useful if we couldn't feed the computer with user data. In this section, we're going to create a program that waits for user input and produces the output based on what the user entered. Open up VS code and create a new file by clicking File and select new file. A new file gets created with the name Untitled one. Save the file using File save As a name it userInput dot p-y. After saving the file type in the following statement, it's important to type it as you see it. Name in lowercase equals input, open parenthesis. For text. Type your name between double quotes and close parenthesis. Now, what are we doing here? Input prompt is a Python function. It prints the prompt string to the terminal and then waits until the user types something and hits enter. The function returns what the user typed, stores it into a variable called name. A variable is a container that can store a value we want to use later in our program. So the name variable stores the value returned by the input function. We assign the value using the assignment operator. Next, type the following statement in a new line. Here we create a formatted string leader or using f strings and assign it to the variable called message. The code f hello name creates a formatted string by replacing the expressions between curly braces with their values. If name has the value Michael, the result will be hello Michael. We're going to talk about strings and string manipulation in more depth later in this course. Now type the last statement. The print function should be already familiar to you. It outputs the value of the text variable to the terminal. Let's summarize what we've implemented. First, we prompt the user to enter a name. Once the user hits the enter key, we store whatever she entered in a variable. Next, we create a new formatted string leader that greets the user. And finally, we print the text greeted at the previous step to the console. Now it's time to test our program. Right-click anywhere in your editor and select Run Python file in terminal. Type a name, I enter, Oscar. Press Enter when you're done. And here's the result. We've just implemented an application that creates an output based on what the user entered. That's a big step forward compared to our first program. 10. 3.3 Using Comments in Code: High-level programming languages have a human-friendly syntax. The code written in a high-level language is way easier to read compared to the binary code. However, as your programs grow in complexity, it becomes harder to understand its logic without additional information. So far, we've implemented to short programs and I explained every statement. This approach works for programming courses and books. You type in the code while following along with the instructor. That's usually not a feasible alternative when coding in real life, wouldn't it be great to include some guidance in the source code itself to explain what your code does. That would help other programmers who may read your code. It might be useful even for yourself, especially if you have to look back at your code a couple of months from now. Luckily, each high-level programming language provides the means to include short inline explanations in the code. These are lines of text called comments. In Python, a line of text that starts with a hash mark sign is a comment. The computer doesn't try to interpret or execute such lines. They are exclusively meant for humans. So here's our code from the previous section. You may remember what each statement does. However, added comments can clarify everything in an instant. Python also supports multi-line comments called documentation strings. A docstring starts and ends with a triple quotation mark, and it's used to provide longer explanation when necessary. The triple quotation mark that ends a multi-line docstring should be on a line by itself. Having that said, you don't have to comment every line of code. So do you write comments? It's a good idea to explain parts of your code that provides specific functionality. You should also comment code that's not straight forward or to clear up confusion. Finally, here are some rules for writing good comments. Comments should be complete sentences, but keep them brief and concise. If your code changes, make sure to also update the comments if required. Helpful comments can help understand your code faster. And as a consequence, reduce the time required to maintain or enhance the program. 11. 3.4 Declaring Variables: We've used variables in the previous lessons. They are containers used to store data that can be accessed or changed. Why the program is running. A variable is a dedicated location from the computer's memory. We tag it with a name that allows us to identify it later. Then we can put a value in it. All right, let's open up VS code. I create a new file as usual, and save it as variables dot p-y. In Python, you create a variable by typing a name. The name represents the data that you want to hold in that variable. So better provide a meaningful one. Say that you need a variable that stores the player's name. Now, you can name your variable x or n, or anything that comes to your mind. But how about this version? It's definitely a better choice as it describes clearly the purpose of this variable. We've just created a variable called name, and we used the equals sign to store the value John in it. It's like saying, hey computer, Here's the variable called name, store the value John in it. Technically speaking, the value john is a string literal. We call literals predefined values that cannot change. The equals sign is called assignment operator, which makes sense as it actually assigns a value. Now, after this line of code, the name variable exists and it can be used to retrieve the value it holds. Bear in mind that you cannot use a variable before declaring it. Let's try to swap the two statements and see what happens. So I select it, press Command X, and place it here using Command V. If I try to run it, we get a name error. Name is not defined. So always make sure to define your variables before using them. All right, let's restore our code to the working version. Variables can be assigned new values after defining them. That's why they are called variables. After all, we can update the value stored in the name variable by assigning it a new value. Running this code produces the following output in the terminal. John and Steve now add another statement. And let's print it too. Now we've got John, Steve, and Sam. Besides providing meaningful descriptive names for our variables, we need to follow certain rules called naming conventions. Variable names should be lowercase. For example, temperature starts with a lowercase t. Or text equals done also starts with a lowercase t. We could change the name of the variable temperature to start with an uppercase T, but that's not recommended. If the variable name consists of multiple words, separate them using underscores, like in the following examples. Other programming languages use the lower CamelCase style for variables. Where do you start with a lowercase word? And on successive words are capitalized, like FirstName, LastName, and so on. Python prefers the underscore separated style as described in the style guide for Python code. In Python, variable names must start with a letter or an underscore. Other characters are not allowed. Type the following statement in a new line. Let's try to run it. The program triggers a syntax error. So don't start your variable names with a number. Let's fix this. All right, Here's a summary of the rules you need to follow when creating your variables. Provide short descriptive names. Start your variable names with a letter. You can also use underscores, but that's a special case and we'll talk about its meaning later. Use the underscore separated style if your variable name consists of multiple words, following the standard naming conventions and coding style will make your code look more professional and easier to understand. Now that you know how to declare a name your variables, let's dig deeper into how we can use them. 12. 3.5 Working with Numbers: We've seen what a variable is, a container that can hold different values with a name that allows us to identify it later and change its value if required. So far, we defined variables that can store text data. Python variables can hold many other data types, including numbers. Besides strings, numbers are the most common kinds of values in computer programs. Now, open Visual Studio Code. Create a new file and save it as numbers dot p-y. Let's define a variable. This line of code tells Python to create a variable called score and store the value 0 in it. Note that I haven't used quotes around the value 0. That would make it a string literal. Although we use the score variable to store numbers, now it holds a string. Bear in mind that most programming languages wouldn't let us change the data type stored in a variable. Once you declare a variable is a number, you can't assign it a string, and vice versa. Python is less restrictive, but that doesn't mean that we should exploit this flexibility. If you want to change the value of the score variable to say 42 million, you should write. As you can see, I haven't used the thousand separator. That's because Comma Separated Values have a different meaning in Python, the following line does not actually change the score to 42 million. Python interprets the comma separated value as a tuple, a list consisting of three elements. The comma separates the elements in the tuple. First, we assign the values for the 200 to r variable. So let's print the value stored in our score variable. I run the file in the terminal. And here we go. The output is indeed a tuple, 4200. So make sure you don't use commas as 1000 separators when defining number literals in Python. We can also use negative numbers. Try this. And now let's print our card balance. The output is minus 200. Now what if you want to use a value that's not a whole number, like say 28.88. We can create decimals by defining number literals that have a point as decimal separator. Python treats the value as a float if the decimal point appears anywhere in it, are the following statements are valid. Don't use whitespaces between the decimal point and the integer or the fractional part. Else, your triggers syntax errors. To create a negative decimal number, you just put the minus sign in front of it. As you can tell, defining numeric values in Python is effortless. So let's do some maths next. 13. 3.6 Using Basic Arithmetic Operations: In this lecture, we introduced the basic arithmetic operations that is addition, subtraction, multiplication, and division, start VS code and create a new file called basic mats dot p-y. Let's create two variables, a and B. I make a equal to 2 and b is four. We can add them together using the plus sign and store the result in a new variable C. Python evaluates whatever is on the right-hand side of the assignment operator and put the result in the variable from the left-hand side of the equal sign. Thus, the following code is not valid. Let's try to run it. And we've got a syntax error. All right, so let's remove this line and make sure to keep the operation on the right-hand side of the assignment operator. Otherwise you'll get a syntax error. As we've seen. The operator for multiplication is the asterisk. For division, we use the forward slash. So these are the basic arithmetic operators. You can't use any other signs or characters to perform these operations. For example, none of the following statements will work. So again, these are bad examples. Let's get rid of them. Python doesn't restrict us to perform a single operation. The following statement is completely valid too. Now, can you guess the result? What will be the value stored in c after evaluating this statement? Let me simplify this for you by replacing the variables with their actual values. Some may be tempted to execute the operations from left to right, like this. 2 plus 2 equals 4, then multiply it by four. So we've got 4 times 4, which gives us 16. Finally, subtract four from 16 and we have 12. Let's print out C and run the program. So why did we get six and not 12? That's because we ignored the order of operations. Most programming languages use the operator precedence levers that conform to the order commonly used in mathematics. Multiplication and division have higher precedence than addition and subtraction. In other words, if an expression has multiple operators, multiplication and division get evaluated before addition and subtraction. Thus, 2 times 4 gets evaluated first, which is eight. Then we add two and we get 10. And finally, subtract four. So the result is indeed six. We can override these precedence rules using parentheses. For example, we could do the following to add together the first two numbers before performing the multiplication. That's rerun it. In this case, the result is indeed 12. Because of the surrounding parentheses, the addition to plus 2 gets evaluated first. So we have 4 times 4 minus for the multiplication, 4 times 4 is performed. Next edit has a higher priority than the subtraction. Then we evaluate 16 minus four. So we've got 12. If an expression contains operations that have the same precedence, python evaluates it from left to right. Consider the following example. X equals eight divided by four, divided by two. Python evaluates the first division starting from left, eight divided by four, which is two, then performs the second division to divide it by two. And the result is one. If we started with the second division, the result would be 4, because 4 divided by 2 is 2 and 8 divided by 2 would be 4. As you can see, the evaluation order matters. So these were the basic arithmetic operators. And we're going to introduce a few more in the upcoming sections, are right, let's talk about string operations next. 14. 3.7 Working with Strings: We've seen how to define string literals. Now let's see some more advanced examples of using and managing taxed in our programs. Open up Visual Studio Code and create a new Python source file called strings dot p-y. Next, create two variables and assign string leaders to them. We can concatenate the two variables using the plus operator. The plus sign here is not an arithmetic operation. Instead, we're telling the computer to concatenate the string literal is stored in Part 2 and Part one and put the result into qualitative variable. Let's check the output by printing the quote variable. There should be a space between the two sentences. Let's fix the formatting issue. We can combine multiple string variables and string literals using the plus operator. So I can insert a whitespace by adding it here. And finally adding part to also. Now we've got the whitespace between the sentences. We could answer create a formatted string literal known as f string. The formatted string literal was introduced in Python 3.6. It's a convenient way to create new strings by evaluating the expression is delimited by curly braces. Here's an example. The code f Part 1 part 2 creates a new string literal by replacing the expressions part one and part two with the value stored in the corresponding variables. As you've probably noticed, the string contains a whitespace separator between the two parts. Thus, the resulting string will be formatted correctly. Let me show you by commenting this statement out and I'm going to clear the terminal. And now let's rerun our file. As you can see, the sentence is correctly formatted because we included a space in the f string itself. Formatted string literals lead us create strings that contain other strings, integers or decimals. Let us type the following. This brings, your name is Michael and your 32 years old. Now, let's try something else. Car, Tesla Roadster. Acceleration is 1.9, and the message equals an f string. The car goes 0 to 60 miles per hour in acceleration seconds. Finally, we print the message. And here's the output. We can include format code syntax within the curly braces of our expressions. Write the following code. Pi equals 3, 14, 15, 9, 2, 6, 53, 59. Next, I construct the message using an f string. Print the message, and it outputs the number pi is approximately equal to and this long number. Now, usually you don't need that high level of accuracy. So let's display only two digits. I'm going to add a format specifier. And talents that I only need two digits, and this is a floating point number. The output contains only two decimals. Using points to F, we specified that the value should be displayed with two digits. You can even get rid of the decimals completely by instructing python to display 0 decimals. Python provides many other useful string features. So let's see some of the most commonly used ones. Given a string literal or a string variable, we can query it's length, that is how many characters it has. I used the land function here. When we run the snippet, it prints out 41 because the number of characters in the message variable is 41. The length will include punctuation and spaces as well. We can also count the length of Unicode strings. We can convert a string to uppercase. Upward is a string method that returns a copy of the string converted to the upper case. Note that the original message remains unchanged. Printing the message variable will print the original string. The upper method has its counterpart that returns the lowercase version of a string. So I'm going to call the lower string method here. There's also a swap keys string method that converts the uppercase characters in a string to lowercase and vice versa. I'm not quite sure about the practical application of the swept case method, but it's there if you need it. We can use the count method to get the occurrence of a sub-string in a string. Let's check how many times we've got the word stay in the original message. So the word stay appears twice in this message. I'll introduce more string related functionality later on in this course. But these were Sufis to get you started. 15. 3.8 The Boolean Data Type: In this lesson, we'll talk about a new data type called Boolean that can only represent the values true and false. Start VS code and create a file called boolean dot p-y. In Python, we define a boolean variable by assigning the value True or false to eat. The values true and false are not surrounded by quotes. They are not string literals, but instead reserved keywords used to create Boolean data types. As you noticed, the keywords true and false must start with a capital. The following statements are invalid as the names true and false, written as they are, are not defined in Python. The keywords true and false are special cases of integers. The value of true is one and false evaluates to 0. And here's the proof. We see 0 in the console because false evaluates to 042 times 0 is 0. And if I replace for us with True, Guess what we get. Now, we have 42 in the console because 42 times true, which is 42 times one, is 42. Although the practical use of Booleans may not be evident at first, they play a crucial role in programming. We can control how our program behaves based on Boolean conditions. For example, we might use a Boolean variable is valid email to control the execution of the program. Initially, the variable is set to false. The East valid email variable becomes true once the user has entered a valid email address. After that, we let our program performed the next action, like loading a webpage or showing registration successful dialogue. We'll get deeper into booleans and conditional logic into the next section. 16. 4.1 Introducing Conditional Code: Programs called rarely executes in a linear fashion. We usually have code that only runs if a specific condition is met. That's what we call conditional logic. The programs we've written so far were quite simple. We started executing the first line and continue to the next one, then the next one, and so on until we reached the last statement. Writing programs this way wouldn't make too much sense. We need to ask questions and make decisions. Even the most straightforward program, we probably need some conditional code. In real life, we have to answer questions and make decisions based on the answers to these questions. Is the traffic light green? If yes, go seeing red, you better stop. Is there enough money in your bank account to cover that overseas trip? If yes, go ahead and book your travel. Similarly, in our programs, we need to have code that only runs if specific conditions are true. That's what we call conditional code. In Python, you write conditional code using the following syntax. The keyword if, followed by a conditional statement and a colon, then the code you want to execute when that condition evaluates to true. If the condition is false, we run the code that comes after the else keyword. The condition isn't a word or a phrase, but rather something in the form if e equals b or if money is less than the balance. The expression that follows the if keyword must break down as being either true or false. Let's continue with an actual example. Open up Visual Studio Code and create a new Python source file called conditional code dot p-y. Type the following code in the editor. First, I declare two variables. Balance represents the bank balance and money is the cash we want to withdraw. Then we have a conditional statement. If balance is greater than money, the colon character marks the end of the if statement. The statements following the conditional statement are four spaces in from the if. And I need to also indent the code that follows the else statement. Now that something new to understand, why did we indent these code lines, we need to introduce the concept of code blocks. 17. 4.2 Code Blocks: A code block is a section of code that gets executed together. Python uses indentation to break down code into blocks. Other programming languages use curly brackets, four blocks. But the creator of the Python language decided to use indentation instead. Fewer special characters mean less typing and less cognitive load for humans. However, it may take some time to get used to it. If you already used C based languages like Java or C Sharp or swift to name a few. Now if I unindent the statements from the if block, I'll get a syntax error. That's because the code that follows a conditional statement needs to belong to a new block. The conditional IF statement is at the level of 0 in dense. The block following the conditional statement must have a higher indentation level. That's how Python knows those statements belong to a block. And that block of code is associated with the if statement. So let's fix our indentation error by restoring the original indentation. Are the statements that belong to a block need to be at the same level of indentation. If I indent any of the statements differently, you'll notice that I'll get syntax errors. Now if I try to run the file, we get an indentation error, unexpected indent for this line, line number 5. So be careful to use proper indentation to delimit your blocks. Python relies on the indentation level to figure out which statements belong together. We'll use blocks a lot as we proceed throughout this course. Now that we clarified what code blocks are for, we can dig deeper into conditional code. 18. 4.3 Comparison Operators: As we've seen, a conditional statement must evaluate to a boolean. In the previous example, we checked if the number is bigger than the other one, and I used the greater than sign to do that. There are also other operators that can be used in conditional statements. Besides greater than, we can check if the value on the left side is greater than or equal, less than, less than or equal to the value on the right. It is also ubiquitous to check for equality and inequality using the equals and not equals operators. Here's the list of the comparison operators you can use in conditional statements. These comparison operators work with numbers, strings, and also other data types that can be compared with each other. Now, let's take a closer look at our previous example. What happens if the amount we want to be thrown matches the balance? It says insufficient funds. So we couldn't retrieve the money because the condition balance is greater than money evaluates to false. Thus, the statement code block will execute that prints insufficient funds. We can fix the issue easily by replacing the greater than with the greater than or equal operator. The rest of the code remains unchanged. Now, this small change will let us withdraw all the money from our bank account. After this transaction, the balance turns 0. Make sure you don't add a space between the greater than and the equals sign, that extra white-space will cause a syntax error. So let's undo our change. The greater than or equal, less than or equal, equals and not equals. Comparison operators must be written together without spaces between them. Another common mistake is using a single equal sign in conditional statements. Let me show you what I mean. First, I create the East true variable and set it to false. If it's true is true, then print true. Else, print false. Can you spot the issue? The East true equals true into code snippet doesn't compare values. It is an assignment, so you shouldn't use it as a condition. In many other programming languages, assigning a value to a variable evaluates to true and the if block gets executed, Python prevents us from making this mistake. Trying to execute this code will trigger a syntax error. All right, So let's recap, follow these rules. When writing conditional code. Keep the less than or equal, greater than or equal equals not equals comparison operators together use the equality operator to check if two values are equal. All right, our examples so far involved both the if and the else statements. However, that's not mandatory. You can use the if statement by itself. I created the is raining variable and initialize it to true. If it's raining is true. We print. Take your umbrella. Bear in mind that you cannot use else without the preceding IF statement. However, nothing stops us from using multiple if statements in a row. The code prints, the number is even, the number is greater than 10 and a dozen. As you may have noticed, I used the new operator. The percentage sign is the modulo operator, which calculates the remainder of the division. If modulo returns 0, there is no remainder. So the number is even. A non-zero remainder means that the number is odd. Since 12 divided by two is six and the remainder is 0, 12 is an even number. Now let's change the value of the number variable to 11. It prints the number is greater than 10. Only one of the if statements evaluates to true. Indeed, 11 is greater than 10, but it's neither even nor equal to 12. Next, we talk about nested conditional statements, and I will show you how to make additional decisions. 19. 4.4 Going Deeper: else-if: As you start using conditions in your programs, you will notice that a pair of if else statements is rarely enough. Many times you will need three or more conditions. One possibility is to use multiple if statements, as we did in this example. Now, there are cases when we need to check multiple conditions and executes the first one that evaluates to true. Take a look at the simplified flow chart of a traffic light. We could use multiple if statements to make it work in Python. If we use the if statements like that, python evaluates each conditional statement is the light green. Yes. So print go, is the light yellow? No, evaluate next if is the light red? No, Next one. Is it flashing? No. The statements code won't run as one of the if statements was true. But we know that the traffic light can only be in one of the states at a time. So why evaluate the other conditions? If we know that the light can only be either green or red or yellow, performing the additional checks is unnecessary. We're just wasting resources and computing time. The solution comes in the form of the elif keyword, which stands for else. If. Let's rewrite our code using an if statement. An if statement can only appear after an if statement. The if statement gets evaluated first. If it's true, the elif and else statements are not evaluated. The first conditional statement, traffic light equals green, is true. Therefore, the three consecutive elif and else statements are skipped. Now, what happens if we assign the value red to the traffic light variable? The condition in the if statement is false. So the first LF gets evaluated next, the expression traffic light equals yellow also evaluates to false. So we process the next LF. Traffic light equals red is true. So Python runs at the associated block of code and print, stop. The penultimate elif and else statements are skipped. As you can see, it printed stop. If you change the traffic light to some invalid value, like blue, none of the if or else if statements or resolve to true. The code block belonging to the statement gets executed, which prints invalid state. 20. 4.5 Nested Conditionals: There may be situations when you want to check for another condition. After a condition evaluates to true. In such cases, you can nest an if statement inside another if statement. You can also add an else or elif statements to a nested if structure. Here's an example. A word of advice. Avoid deeply nested code. Normally, you shouldn't go beyond two levels of nesting. Otherwise, your code becomes overly complex and hard to understand. In programming, deep nesting is a problem known as the arrow anti-pattern. The name comes from the shape of nested if statements. Boolean operators allow us to combine multiple conditional expressions without relying on nested if statements. So hanging in there, we talk about Boolean operators. Next. 21. 4.6 Using Logical Operators: Let's examine the code snippet with the nested if statements. I'm going to delete our arrow anti-pattern example. And let's crop up. Alright. The first if statement checks if the traffic light is red, the nested IF checks if is blinking is true. So basically we're asking if the traffic light is red and it is blinking at the same time. What if we could express both conditions at once? Actually, we can do that. The statement above is completely valid. Python code, the end word is one of the three Boolean operators, also known as logical operators. The AND operator takes two expressions and it returns true only if both expressions are true. Otherwise it evaluates to false. Now, I'm going to remove this line. And let's try out something as I create a Boolean variable called success, and let's initialize it to true. And here's the second variable called result code. Next, I'm going to check if success is true and result code equals 200. If both success equals true and result code is 200, I print success. Else, print failure. If you run this code, it prints success. Both expressions in the if statement resolves to true. So we have true and true, which evaluates to true. Now, assigned a value falls to the success variable. And let's execute the code again. This time, the condition in the if statement becomes false equals true and true. Now, false equals true is false. So the condition boils down to false and true. The result is false because the AND logical operator returns false if any of the expressions are false. Or logical operator takes two expressions, two, it returns true only if any of the expressions are true. Now, let's type the following code in your Visual Studio code editor. I'm going to close this one and let's scroll it up. I create a variable called firstName. And let's assign the string literal Alan to it and lastName. Make it Ripley. And next we check for the length of the firstName and lastName. In the if statement, I use the logical OR operator to check if both firstName and lastName have a valid length. If either is empty, we prompt the user to enter her name. Otherwise, the program greets the user. And I'll be using an f string here, which says high. And the value of firstName and last name. The program will print, hi Ellen Ripley. Let's try it out. Awesome. Now let's follow through what's happening in the if statement. Land firstName equals 0 resolves to false since the text stored in firstName Allen is five characters long, landless name equals 0 also evaluates to false. Ripley has six characters. So we have false or false, which evaluates to false. So the ass statements code block gets executed. The third logical operator is not. The not operator takes a single expression and you can use it to negate a Boolean expression. In other words, placing not in front of a Boolean expression reverses its meaning. Let's go back to VS code and type the following. Here, we check if a user is not an administrator. Not admin user resolves to not false, which is true. Thus, the program runs the code block associated with the if statement. Let's run it. Indeed, we've got permission denied in the terminal. Now you know how to write conditional code in Python to solidify the concepts, play around with the exercise code and see what happens if you make some changes. 22. 5.1 Why Do We Need Functions?: In this section, we'll dive into functions. Functions allow us to write code and reuse it anywhere in our programs. So why is reusability important? Let me start by showing you an example. Let's start Visual Studio code. Next, I create a new Python source file called functions.php. Why? We write a program that computes the area of a rectangle. I start by printing a message to the terminal. I declare two variables, length and width. Let's make it five. And with say, four. To calculate the area of the rectangle, we multiply length by width. And let's print the result using an f string. This code creates two variables, length and width, and assigns them the values 54. Then we calculate the area of the rectangle by multiplying the length by width. Finally, I print a formatted string that displays the area. And let's check the output. It says the area of a rectangle with length five and width four is 20, correct? Now, what if we want to calculate the area of another rectangle which has a length of say, 21 and width of 12. We can do that by changing the values of length and width. I rerun the app. The area has changed as expected. Now, what's the issue with this code? Whenever we want to calculate the area of a new rectangle, we need to update the values assigned to length and width. What if I need this functionality later in my program? Let's say that we added a dozen new statements. And we need to calculate the area of a new rectangle after executing our code. So what do you do? You copy and paste the snippet whenever you need it? However, that's not a good idea. You end up having the same redundant code spread throughout your code base. And only length and width would change. Our program becomes messy as we keep adding more and more redundant code. The code base keeps growing up to the point where it's almost impossible to understand what it is doing. You should avoid redundancy in your code. Dry. Dry is the acronym for don't repeat yourself. A programming principle that aims to reduce a repetition of all kind in order to create a cleaner codebase. All programming languages provide a way of grouping parts of code and making them reusable. In Python, we call these reusable pieces of functionality functions. We talk about creating and using functions next. 23. 5.2 Writing Functions: We can create functions to wrap the code that we want to reuse. Use the following syntax to define a function in Python, the def keyword shows that we are defining a function, put a space after death and specify the function's name. Function names should be lowercase and use an underscore to separate the words. Theoretically, you could name your functions anything you want. However, it is recommended to provide meaningful names which describe what your function does. Since the function defines a specific functionality, it is recommended to start its name with the verb, such as authenticate, calculate, or fetch. You can add a noun to increase the clarity further, like, for example, authenticate user, calculate area or fetch sales data. The function name is followed by a pair of opening and closing parentheses. Inside the parentheses, we can specify the data you want to use in your function. If the function doesn't expect any data, you can leave the parentheses empty. Otherwise, list the data you want your function to accept. The input data a function takes is called a parameter. Here's a function that takes a single parameter. If your function takes multiple parameters, you need to separate them by commas. A column follows the closing parenthesis. This column tells Python that we're done with the function's declaration and the function's code comes next. The function's code block must start in a new line after the colon, and the code needs to be indented. The code block is called the function body, and it contains the statements that execute when the function gets called. A function can contain one statement or many more lines of code. Usually, functional shouldn't be too long and there are best practices to prevent the proliferation of code within functions. We'll get to these techniques later. If the function needs to return a value, use the return keyword followed by the value or the expression that provides the returned value. Now, let's start Visual Studio Code. Open the functions.php file we created in the previous lesson. We're going to clean up this mess. So I'm going to select all and hit Delete. And now you're going to implement your very first Python function. First, define the function. The name is descriptive. You can tell what this function is supposed to do just by looking at it. Calculates square area, takes a single parameter called side. Alright, now let's implement it. To find the area of a square, we need to multiply the length of its sides with itself. The function takes the side parameter that's needed to perform the calculation. Thus, we can write the following code. Area equals side, multiplied by side. Let's return the result. Actually, we can get rid of the area variable and return the side multiplied by side expression. All right, we just defined a function in Python. So let's start using it. 24. 5.3 Calling Functions: After defining our function, we can use it from anywhere in our program. However, a functional scope isn't executed automatically. Python has no way to know when do you want to run the functions code? We need to write the code that causes the function and pass in the input data if there's any. We've already used some of Python's built-in functions. You probably recall the print or the input functions used in the previous lessons. We can call any function, including the ones we create in a similar fashion, we type its name and pass in the arguments. There is the values for its parameters if it has any. So I can call our function by typing its name. Calculates square area. And I pass in the value five for each parameter. Bear in mind that there's a clear distinction between function parameters and arguments. We use the term parameter when we define a function. Upon invoking a function, the values that we pass in are called arguments. In this function declaration side is a parameter, whereas when we use the function five is an argument. Now that you know the difference between a function parameter and an argument, let's analyze the code further. Although the function's code will run, we can see the result. Let's run our code. There is no output. Although the function's code was executed, we can't see the result. That's because we haven't used the value returned by this call. We can easily change that. I'm going to assign the result of the function call to a variable. And let's also print the result. Now we can see the result of our function call. I can add further code and invoke the function when I need it. And so on and so on. Functions help us structure our code in the units that can be called whenever we need that particular functionality. I know it's been a long haul, but we're not done yet. Next, I'll show you how to make your functions more foolproof. 25. 5.4 Defining Function Parameter and Return Type: Awesome. You know how to define and use functions. There's a problem we need to solve though. Currently, nothing prevents us from riding the following. Trying to execute this statement triggers on error. We can pass in any type of argument to our function because there are no restrictions regarding the parameter's type. However, the multiplication only makes sense for numbers. Python 3 and above allow us to annotate function parameters and provide type information. Annotations for parameters take the following form. So we can annotate the type of the parameter r function accepts as follows. Parameter type annotations informed the color about the expected argument type. Note however, that the color may still provide an invalid argument. Unlike many other programming languages, python doesn't impose any restrictions based on the parameters type. We can also annotate the type of a functions return type. Here's how we would specify that the calculate square area function returns an integer. Besides type information, we can also provide default parameter values using the following syntax. Let's provide the default value of one to the side parameter. The side parameter became optional because it has a default value. We can call the function without passing in an argument. Okay, Let's get rid of this line. And I'm going to call the function without passing in an argument. Here's what happens. Because the sides parameters default value is one, the function return one. The default value for parameters is useful if a function gets called with a specific value most of the time. To consider the following example, I define a function that creates Ferrari's. The function takes a parameter called color, and I provide a default value of red. The most popular Ferrari color is red, so it's an obvious choice to make red the default value for the color parameter, calling the function without providing a value, we'll print, build a red Ferrari. But if we pass in a color, that value will override the default one. Let's build a blue one. And here's our blue for RA. The parameter and return value and notations are optional in Python. Use annotations whenever they improve the clarity of your code. 26. 5.5 Understanding the Scope of Variables: To illustrate the problem we discussed in this lesson, I'm going to make some changes to our function. First, I'm going to delete this part as we don't need it anymore. And now, instead of using the area variable outside our function, I'm going to declare it inside the functions code block. So let's delete it from here. And I'm going to redeclare it inside the function. Area equals side, multiplied by side. And let's return it. And now I try to run this code. We got an error. It says name error. Name area is not defined. That's strange, right, since we declared the area variable here. So why is it invisible at this point? To understand why Python insists that area is undefined, we need to talk about the scope of variables. Any variable that's defined within a function has a local scope. That is, it can only be used inside the function where we declared it. Let's take a look at the definition of R calculate square area function. We can access the variable within the function scope without problems. For example, I could insert a new print statement that reads the area variable. I need to comment this line out. And if I run the file, it compiles just fine. However, the area variable is not available in the code that's outside the calculate square area function. So again, if I uncomment this line, we'll get the usual error. Yeah, it says name area is not defined. Python treats it in a similar way as if it wasn't defined at all. Hence, we got the name error. If you need a variable that's visible both outside and inside the function, you need to declare it at the global scope. Then here's how to do it. This is a global variable. Now, let's pass in a valid value, say for, for the side and rerun the demo. Although this code compiled without errors, it produced unexpected results. The area should be 16, but we got 0 instead. We still see that the area that is printed inside the function is correct. It's 16, but the second time we print it, it gives us 0. That's the initial value of the global area variable. In fact, the calculate square area function did not actually change the value of the global area variable. Instead, it created a local one inside the function. Now we have a global and the local area variable. The function assigns the result of the multiplication to the local area variable and leaves the global area variable unchanged. Python requires us to specify that we want to access a global variable inside the local scope explicitly by re-declaring it using the global keyword, we tell Python that we know what we're doing and we indeed 12 change the global area variable. The safety measure is needed to prevent accidental changes to global variables defined outside of a function. After these changes, we should see the right result. All right, Now both print statements are in sync. The global keyword allows us to access global variables at the local scope. However, as a rule of thumb, you should avoid relying on global variables in your functions. Global variables represent unprotected data that might be accessed or changed by any function in the system without notice. Instead, you should pass in the data required by our function as arguments and use the return value after calling your functions. Next will solidify everything you've learned so far by implementing a more advanced Python program. 27. 5.6 Demo: Implementing an Area Calculator: You know a lot about programming in Python already. So let's implement a slightly more advanced program. We're going to write an application that calculates the area of circles, squares, and rectangles. You'll be using conditional code, ask for user input, and you're also going to implement functions. All right, Let's start Visual Studio Code. I create a new file called area calculator dot p-y. We define the function that calculates the area of a square. First. It takes a parameter called side of type float. The function multiplies the length of a side by itself to find the area of the square and returns the result. The second function is called calculate rectangle area. It computes the area of a rectangle. The function takes two parameters, the length and the width of a rectangle. We multiply the values of the input arguments to find the rectangle's area. The last function calculates the area of a circle using the following formula. Area equals Pi times r squared, which is equivalent to Area equals Pi times r times r. Here, r represents the circle has radius and Pi. The Greek Pi letter is a constant, which is approximately equal to 3.14. That's the ratio of the circumference of any circle to its diameter. We could also use the exponentiation operator to raise the radius to the power of two. 28. 5.7 Testing the Application: We now have all the three functions to calculate the area of squares, rectangles, and circles. Let's print some information to the terminal. I am using a multiline string literal to display the string wrapped as you see it in the code editor. If you want to create multiline strings, surround them with triple quotation marks. Any line breaks, tabs or quotes will be included into resulting string. So this code prints exactly what I typed in the editor. All right, let's continue. Next. We ask the user to select the shape. We're using the built-in input function that prints the prompt string to the terminal and then waits until the user types something and hits enter the backslash d sequence here inserts a tab to indent the text after it. The user should type as R or C to select the shape. We then use conditional logic to calculate the area of the chosen shape. First, I define an area variable and initialize it to 0. And now I'm going to implement the conditional logic. The if statement checks if the user pressed as foursquare. The if block prompts the user to enter a value for the squares side and assigns it to the variable side. The second statement cause the calculate square area function and passes in the value of the side variable. The value returned by the calculate square area is assigned to the area variable. Note that I had to convert. The value is provided by the user to float using the built-in float function, we need to perform this conversion because input returns a string and we cannot multiply two strings. As a side note, this conversion to float might fail since the user can enter any value. We leave the code as it is for now. Later, I'm going to show you how to handle conversion errors and other problems. If the user didn't select a square, he might have picked a rectangle. Lf selection equals r. Now I ask for user input for the width and the length of the rectangle has sides. I create a length variable and assign it to the value returned by the input function. And same for width. And finally, let's calculate the area I'm going to call Catholic rectangle area and pass in the values for length and width. I need to make the conversion to float as in the previous case. Now, if the user has selected neither a square nor a rectangle, check if he entered a C for circle. Lf selection equals C. Here, we need to ask the user to input the radius. So I create a variable called radius equals. And again, I'll be using the input function. And area should be equal to calculate circle area in this case. And I convert radius to float. Finally, the else statement gets executed if the user pressed any other key else. And we just print a warning which says invalid selection, choose S, R, or C. Last but not least, we print a formatted string that displays the area of the shape or 0. For an invalid selection, I use an f string and print the area. And now I run the app. Let's start with a square. The side is 12, and indeed the area is 144. Another run, now I select the circle, radius, say 42. Okay? And now a rectangle, the length should be say 10. And with Penny three. And now I input an invalid selection, say x. We've got our warning message. Alright, awesome, our app works as expected. Next, we're going to make some enhancements. 29. 5.8 Enhancing the Area Calculator App: We can enhance this application further by encapsulating all the conditional logic into a separate function. So we're going to move all this part into a dedicated function. Let's create a function called calculate area first. And now I copy and paste this chunk of code, which starts with the declaration of the area variable and ends with the else statements block, press Command X, and paste it here using Command V. We need to increase the indentation level of every line of code that's now part of the calculate area function body. Python will complain if you don't indent the code properly. If I try to run this code now, I will get indentation errors. All right, so let's make the changes. Just go to the beginning of each line and hit tab. So here's what you should end up with. And the function needs to return the calculated area. Next, let's implement a function that returns a textual description of the shape type that's been selected by the user. Programmers create such helper functions whenever it makes sense. Let's scroll down. And I create the function gets shaped name. It takes a tag parameter, which is the character entered by the user. I define the shape variable which will be returned by this function. I initialize it with a string literal unknown. And now let's check the tags value. If tag equals S, the shape is a square. As if the tag is, are the shape is a rectangle. Another valid value is C for circle. And we accept no other values for now. So I just return the shape. The function takes a single parameter called tag that represents a user's shape selection. The functions block defines a variable shape and initialize it with a text unknown. Then it checks for the valid entries and assigns the corresponding shape description. If none of the conditions are true, the shape variable won't change and it keeps its initial value which is unknown. Finally, the function returns the value of the variable shape. After all these changes, we can reduce our testing code to the following. Area equals calculate area selection. And I enhance the string we output to the terminal by printing the shapes name, the area of the. And here I'll be using our helper function. Gets shaped name selection. Let's run the application. I start with a rectangle. Are okay, we've got an error. It says calculate area takes 0 positional arguments, but one was given. Indeed, I forgot to add the selection parameter, so let's do it now. Okay, let's run it again. I pick a rectangle. The length should be 20 to the width, say 12. And now the string printed to the terminal also includes the shapes type. It says the area of the rectangle is 264. Let's see for square, the side 55. We haven't tried the circle yet. Let's enter a radius of say, 45. Brilliant. You just finished your first Python program that has a practical value. 30. 5.9 Challenge: Calculate Rhombus Area: As an exercise, enhances the app with the option to calculate the area of a rhombus using the following formula. Area equals p multiplied by q divided by 2. P and q are the diagonal of the rhombus. I give you some hints. First, you should create a new function, let's say calculate rhombus area that takes two parameters, p and q. Then implement the code based on the formula above. You should also allow the user to select the rhombus by including a dedicated character in the prompt text. And don't forget to add an if block for the new shape in both the calculate area and the good shape name functions. 31. 5.10 Solution: Calculate Rhombus Area: Here's a solution for our section challenge. Let's start by creating the function that calculates the area of a rhombus. I inserted here and call it calculate rhombus area. We should pass in p and q. The diagonals. Both of type float. And the function relies on the formula. Area equals p times q divided by 2. Next, I allow the user to select the new shape by enhancing the selection prompt string, indent. And for rhombus, I'm going to use H since R is already taken. What comes next? We need to enhance the calculate area function as well. If selection is h, we ask the user to input P and Q. Now we have the diagonals. Let's calculate the area by calling calculate rhombus area. Let's add H. And finally, I need to enhance the helper function gets shaped name. If the tag was h, the shape is a rhombus. Let's execute our program. It looks good to me. The function works as before, except that now we can also calculate the area of a rhombus. All right, that's it. Now you should be able to define functions in Python. Next, we're going to talk about another crucial programming concept, the loop. 32. 6.1 What's Iteration in Programming?: In programming, you will encounter situations when you've got to repeat certain tasks. Consider the following. We need to write a function that Laozi and the user based on a username and a password. Quite a common scenario, isn't it? If the login credentials are wrong, we prompted the user to re-enter the username and the password. We could start by implementing the login function. So fire up VS code and create a new file called login dot PY. And I'm going to save it as login dot p-y. I define a function called login. The function takes two parameters, username and password, both of type string. And we return a Boolean indicating if the login was successful or not. In the function's body, we define the authenticated variable and initialize it to false. And now comes the authentication logic. The if statement performance or basic username and password check. To keep it simple, we just compare the username and the password against predefined string literals. This approach is fine for this demo, but you should never use it in production code. The function returns the value of the isAuthenticated variable. Next, we'll use the function to authenticate the user. But first, let's prompt the user to enter the login credentials. I use the input function again to retrieve the username and the password. Now called the login function with the provided username and password. The result of the call gets stored in the logged invariable. I pass in the value of the user and the password. Then define the message variable and assign it the string literal with the message for the failed case. How about Login failed, check your credentials. If the login was successful, we update the message accordingly. And finally, let's print the message. Now, we could make this part shorter. I show you a technique that relies on conditional expressions. So let's comment this out. And instead write the following. Here, I use a conditional expression to print the right message based on the logged invariable conditional expressions, also known as ternary operators, take the form expression e if condition as expression be. If condition is true, expression a gets evaluated and its value returned. Otherwise, the result of evaluating expression B gets returned. Here's the complete source code we've written so far. We can remove this part and it becomes shorter. Okay, let's try it out. Right-click in the editor and select Run Python file in terminal. I enter the expected credentials for a username admin, and the password 1234. Login, successful, great. Now rerun the program. This time I'm going to use some random usernames or passwords. Let's see what happens. Username, say Michael and password, office login failed, check your credentials. That's the result we expected. However, instead of asking the user to re-enter the credentials, the application exits normally with prompted the user until the login is successful. So how do you do this? With need to write code that first prompt the user for login credentials. Then cause the login function with a username and a password. If lugging returns false, go back to step 1, otherwise, continue with whatever follows the login part. We could express this logic by saying, repeat asking for user input until login succeeds or Y login not successful, ask for user credentials. That's almost exactly how we're going to implement our logic in Python. 33. 6.2 Introducing the while Statement: In Python, like in many sea-based programming languages, we can use the while statement to repeat execution until an expression becomes false. Here's the general form of the while statement. Note that the else clause is optional so you can skip it and right, while expression and then the code block, the code that belongs to the wild clause gets repeatedly executed as long as the expression is true. In other words, the while loop tests a conditional expression and runs the body of the loop while the condition remains true. Let's use the while statement in our login program to make it asks the user for credentials until the login succeeds. We'll implement the logic in the form Y login, not successful, keep asking for username and password. All right, Start VS Code and open the login dot PY file. If you don't have it open already. We're going to remove all the code up to line 11. Next implemented the while loop. It tests the conditional statement that follows the while keyword. In our case, we want to check if the login failed. If the login function returns false, meaning that the login failed, the condition login equals false evaluates to false equals false, which is true. The expression login equals false may look counter-intuitive at first, but it's actually like saying, did the login fail? And if the response is yes, the login failed, then we proceed with the loops code. The loop's body consists of three statements. First, I print a warning message telling the user that the login failed and he should re-enter his credentials. Then we ask for the username and password using the input function. Basically, we repeat this sequence. After executing the statements, we jump back to the start of the while loop and check the login equals false condition. Again. This happens over and over again until login equals false, evaluates to false. When does this occur? When the login function returns true? That is, when the condition becomes true equals false, which is false. Thus, the while loop will exit if the user enters the right credentials. Admin and 1, 2, 3, 4 for password, the code that follows the wild statement gets executed. Next, let's add the success message after the while loop. All right, let's try it out. I enter a wrong credentials and office login failed, re-enter your credentials and we're prompted again. Now, how about Dwight? Password on x to y? And now I enter the right credentials. Login successful. The program keeps asking for the right credentials until login returns true. After two failed attempts, I entered the correct username and password, and the login succeeded. Nice, but not perfect, as we'll see shortly. 34. 6.3 Avoiding Infinite Loops: In the previous lesson, we created a program that asks for user credentials. We relied on the while statement to keep asking for the username and the password until the login succeeds. Now, what happens if the user has forgotten his password? The while statement, while loop forever, or until you shut down the computer. That's known as an infinite loop. And it's one of the nastiest bugs that can pop up in your programs. As a rule of thumb, we should avoid infinite loops by providing an exit condition. The exit condition needs to make sure that the loop will terminate. Now, let's revisit our program. As you probably know, authentication doesn't work that way. You get punished after too many unsuccessful login attempts. In the worst case, you may be even locked out of your own account. We're going to implement this behavior shortly. We need to be able to track the number of unsuccessful login attempts. First, create a variable called attempt and inserted between the statements that ask for user input and the while loop. So here at line ten, I'm going to add a new line and create our new variable, initialize it to one. Next, I create a variable called max attempts. The max attempts variable stores the maximum number of allowed unsuccessful login attempts. And finally, we need a Boolean variable that shows if the login was successful, I call it, is authenticated and initialize it to false. Will only set it to true if the login succeeds. Whenever the user enters wrong credentials, we increment the value of the attempt to variable. Let me scroll up a bit. I insert a new line and I increment the value of the attempt variable right at the beginning of the while code block tempt equals attempt plus 1. We could also use the plus equals operator to increase attempt by one. So we could make it shorter like this. I prefer this version, but both will work. Next. Jackie, if they attempt count is within the acceptable range by comparing it to max attempt. If it's greater, we should exit the loop and lock the account. I just introduced a new statement. Break. The break statement can only appear in a loop and it terminates the loop instantly. The rest of the loops code gets skipped, including the else clause if there was any. In our case, that means that the print and the next two statements won't be executed. If the login is successful, we added is authenticated from false to true in the else clause. As you may recall, as gets called when the expression in the wild statement is no longer true. That is, when the login succeeds. I said is authenticated to true. And print login successful. I'm going to move this line into the ASP code block. After the loop will check the ys authenticated variable and inform the user that his account was locked. We're using the NOT logical operator that negates the value of the expression that follows it. Thus not is authenticated becomes true. If is authenticated is false. So here's the full listing. We have our method and now we check for the number of attempts. If attempt is bigger than max attempts, that is bigger than five, we lock the account and print. Your account has been temporarily locked. Let's try it out. I just enter some random values, a, b1, b2, whatever. One more time. And finally, that was the fifth attempt. Right here is the message. Your account has been temporarily locked. 35. 6.4 Writing for-in Loops: The while statement allows us to repeat the execution of a block of code as long as the condition evaluates to true. There are many cases when we need to keep track of an index of some kind to ensure that we don't loop forever. In our previous example, the attempt variable was such an index and attempt is greater than max attempts was the exit condition of our loop. Thus, the loop won't repeat more than five times, no matter what. Sometimes that's precisely what we want in our programs. Execute a block of code a number of times, then exit. The Python for statement provides this type of functionality. Let's create a new Python file and call it for loops dot p-y. Here's your first for loop. The range built in function generates integers from 0 up to, but not including the provided stopped value. Thus, range five creates the sequence of integers 0, 1, 2, 3, 4. The for loop iterates over the elements of this sequence. That's why the range function is generally used in for loops. This code snippet prints card from the inner for loop five times. Let's try it out. Next, I'm going to print the index and the iteration count. Since index starts at 0, I had to increment it to display the iteration count. I comment out this line and let's rerun it. The arrange function takes three parameters out of which the start and step are optional. We can specify the lower limit by providing the start argument when calling the arrange function, range 1, 5, generate the sequence 1, 2, 3, 4. Just like in our previous example, the value of the stop argument, which is five, is not included in the result. The step parameter specifies the difference between each consecutive number in the sequence. Range 1, 5, 2 creates the sequence 1, 3. The sequence starts at one. The step is two, so we keep incrementing the numbers by two. The second number becomes three, and the third number would be 5. However, we reach the stop value five. So five is not included in the sequence. Both start and step are optional. If we don't specify these arguments, the default values applied, which are 0 for start and one for step. It's worth highlighting the difference between the while and the for loop. The while loop executes until the condition is no longer true. Whereas the for-loop runs a block of code a finite amount of times. 36. 6.5 Deeper into Loop Control Statements: We've seen that the break statement can be used to exit the while loop prematurely. You can use it with a for loop and the effect is the same. It instantly breaks out the loop and execution continues after the loop. Now, let's modify the for loop as follows. This condition checks if the index is two and then it breaks out of the for loop. So our for loop will execute the first time because the index is 0, that's the starting value. It will print index 0 and index plus one iteration count, that is one. The next iteration we'll print index one and iteration count two, since index is 11 equals two is false, so we don't break yet. However, the third iteration is when the index becomes two. Index is two, meaning that two equals two is true. So we break out the loop. Let's check it out. Clean our console, and now let's run our Python file. Indeed, we see that two iterations here. There's another statement that's available for controlling loops. The continue statement can be used to skip the rest of the code block and start executing the next iteration right away. Let's replace line number three with the following. The condition at line number three checks if the index is perfectly divisible by two with no remainder. Here, I use the percentage sign, which represents the modulo arithmetic operator. This calculates the remainder. The expression n modulo 2 equals 0 evaluates to true for even and two false for odd numbers. Let's see some examples. One modular 2 is 1. That's because two goes into 10 times, so the remainder is 1. We could also express it this way. 1 is 2 times 0 plus one to modulo 2 is 0, because two goes into two exactly one time and the remainder is 0. Again, we could write this as 2 equals 2 times 1 plus 0. For any odd number, the remainder of a division by two is one, whereas even numbers are perfectly divisible by two. Alright, let's delete these lines and go back to our for loop. If the number is even, the continue statement skips the rest of the code block. As a consequence, only the odd numbers get printed. Let's see the result. I'm going to run the Python file again. And we can see we print the index 1 and 3. Only the odd indices get printed. As an exercise, modify this code to print the even numbers. It's pretty easy. You should only modify the condition here at line 3. To summarize, you can use the continue and the break statement with both the four and the y loops. It is important to remember the difference between the two loop control statements. Break exits the current loop, whereas continue shortcuts the loop and start the next iteration. 37. 6.6 Rewriting the Login App Using the for Loop: In this video, we refactor the login program we implemented at the beginning of this chapter. So start VS Code and open the login dot PY file. Now select File, Save As, and save the file as login using for loop dot p-y. Next, delete all the code except the login function and the two statements asking for user input will also need the isAuthenticated boolean variable. So keep that line too. You should end up with the following code. The login function, the user input queries, and the isAuthenticated Boolean variable. We can also delete the attempt and the max attempts of area was as well. We won't use them anymore. Now we're going to implement a version that relies on the for statement. The overall logic should stay the same. We let the user enter the credentials for more times after the first attempt, that is five times in total. This can be expressed with the following for loop. Next car, the login function. If it returns true, set the isAuthenticated variable to true, and terminate the loop using the break statement. Otherwise, print a warning. So I'm using else and print login failed, re-enter your credentials. And we ask the user to enter the username and password using the input function. Actually, we can copy the code from here. Command C or Control C on Windows and Command V, or Control V on a Mac. That's indented. And that's the for-loops complete code. After the loop, I use a conditional expression to print the right message based on the value of the isAuthenticated variable. I print login. Successful. If is authenticated is true. Else we lock the account temporarily. If isAuthenticated has not been set to true, that means that the user made five failed attempts to enter the credentials and we lock his account. Here's the full listing. As you can see, this version is shorter and cleaner compared to the version with the while loop, because we don't have to increment and check the attempt variable manually. And finally, here are a couple of simple rules that will help you identify which loop statement to choose. Use the while loop to execute a block of code as long as a condition is true. And choose the for loop to repeat your code a fixed number of times. Alright? In this section, you've learned a lot about loops. It's time to move on to a different topic. 38. 7.1 Storing Multiple Values: You already know how to work with variables that hold individual pieces of data, such as a single number, one string, or one Boolean. They did an excellent job in other demos we've built so far. However, there are situations when we need to represent collections of items. Imagine that you want to build an application that lists your favorite restaurants or the names of your followers on Twitter. You could use a variable of type string and include that data. But how would you retrieve or modify a particular item from that string? Effectively, we need a better way to organize our data. Python provides data types that can hold multiple values. The sequence is the most basic data structure, and it stores the items in a specific order. Each element has an index associated with it, which represents its position within the sequence. We've got six names in this list, and each has an index. Note that the indices start at 0. Treating them as if they started with one is a common programming mistake. So if you have a sequence of six items, the indices go from 0 to five, and not from one to six. Can access and modify the contents of a sequence using their indices. We'll talk later about more advanced data structures that lead us access the elements through unique keys. But first, let's delve into sequences. Python has six different built-in sequence types. We're going to talk about the most common ones, the list and the tuple. 39. 7.2 Creating Lists: Let's start with the most frequently used container type, the list. A list lets us store multiple elements in a specific order. I suggest you follow along with me by typing and trying out the code that's discussed in this section. Start VS code and create a new file called lists dot BY File, New. Save it as lists dot p-y. We can use the following syntax to create a list. The list function creates an empty list. If we want to use it, we need to assign the returned empty list to a variable. Printing the list shows that it's indeed empty. The brackets in the terminal log denote a list and we can actually initialize a list using this syntax. So we could write primes equals, open and close bracket. We can add elements using the list append method. We'll talk about the difference between methods and functions in the introduction to object oriented programming chapter, primes dot append, and let's append some prime numbers. We start with two. Now I copy this line and the next prime is 3, 5, 7, and the last 111. Let's print it out. And here we go. The argument passed to the append method gets added to the end of the list. You can see how the list changes by adding a new element. And now run the file again. As you can see, 13 has been added to the end of the list. Using the bracket syntax, we can provide the list elements upon its creation. So instead of appending the elements, we could write the following. And the result is the same. The resulting list is mutable also in this case. So we can add new elements to the end of the list using the append. That's append 13 and 17. We're not restricted to storing integers in a list. Here's a list that contains strings. Name's Michael, Dwight, and say Pam. And we can have lists of Boolean values as well. Values equals true, false, false, true. Python, unlike most sea-based languages, allows the mixing of types within the same list. The following listing is completely valid. Bag equals. Let's initialize it with integers on to three. Then append a string, let's say Pam. Then I append a Boolean, and again a number. Finally, let's print our bags contents. 40. 7.3 Accessing List Items: Each element in a list has an index associated with it. The index is zero-based and it gets incremented for each consecutive item given the following list, the indices of the items are 0 for Michael, 14 divide into four PAM. To access an element in the list, we use the name of the list variable followed by the index operator. Inside the brackets, we specify the elements index, the following expression, list. And here you have to provide an index returns the element with the given index. Now, can you tell me the value of the name variable after executing this statement? Pause the lesson and take some time to think. Ready? So let's double-check your answer. The item at index 0 is Michael. Dwight has the index one, and Pam is at index 2. Thus, the correct answer is Pam. What happens if we try this? There is no element at index three. Accessing an index that doesn't exist will trigger an index error. To avoid such errors, we could check the index before using it. A list index should not be negative and it must be smaller than the number of items in that list. We can express these conditions as follows. Let's build a helper function that validates the index before using it. I called the function is valid index. And it takes two parameters, the index of type integer and the list we want to access using the specified index. It returns a Boolean. Next, create a variable that represents a result and initialize it to false. If the index is within the acceptable range, we update the result true. Otherwise, it keeps its original value, which is false. And finally, let's return the result. Now we can use this function to validate the index prior to using it. I'm going to delete this line. And let's check an index. Say index is three. And we'll use an f string. I output a message here, index. And the value of index is valid. If I call our new helper function. If it's valid, index, index and I provide our list. Else. Index is out of range. Now I run our program. As you might have observed, I am using this run Python file in terminal shortcut button here. If you have the latest VSCode version, you should also see this button. It's equivalent to using the right-click context menu and run Python file in Terminal. So let's just press the green triangle. And here's our message. Index three is out of range. If I change it to two, it should be a valid. Index. Two is valid, and you can play around with it. Say 13 is obviously invalid. 0 should be valid. And how about minus1 out of range as well? So it works. All right, We've seen how to access the items of a list and we even implemented a function to validate the indices. We'll talk about modifying the contents of the list next. 41. 7.4 Modifying the Contents of a List: We've seen how to retrieve the items from a list. Accessing an element through its index returns the element at that position, but it doesn't modify or remove it. To update an element in the list, we can assign it a new value using the bracket syntax. Now starts VS code and create a new file called modifying lists dot p-y. First, I declare a list called primes. In this example, we're going to modify the element at index 1 in the primes list. Let's make it equal to 17. The item at index 1 gets replaced with a new value. I insert two print statements to visualize what's happening here. And now let's print the list also after the change. As you can see, three has been replaced with 17. If we use an index that doesn't exist, we'll get an index error, add the following line and run the program. So let's make the element at index five equal to 19. We don't have anything at index five. If you check the primes list, it only has five elements, which means it's last index is four. Remember, we start indexing with 0. So the first index is 0, 1, 2, 3, 4. There's nothing at index five. That's why we get this index error. So I'm going to remove this line. We can use the append list method to add a new element to a list instead of replacing existing ones. Let's append 13. The new element gets appended, that is added to the end of the list. Let's print our list. And here, 13 has been added to the end of the list. The list size gets incremented after each Japan's call. If the list was empty, A-band adds the element of the list and the list size becomes 1. Let's write some code. I create a new variable called characters and initialize it with an empty list. Now, let's append a character, say a, and I print its length. Here. I'm using the Len built-in function. And the output shows the length of the characters list. We can make it more user-friendly by using an f string. And let's rerun the program. There are cases when we want to insert the new element at a given position. The Insert list method inserts the new value just before the element at the specified index. The existing items with an index greater than or equal to the specified index get moved one position to the right. Let's inspect the following statement. And I provide an index of one and the value 3. This line inserts the value three at index 1 into the primes list. All the existing list items starting at index 1 are shifted one position to the right. Finally, the new value gets inserted at index one. And here's the resulting list. You can see the number 3 appeared after two at index one and 17, which used to be at index one is now at index 2. Or the other elements have been shifted one position to the right. Two stays in place because it was at a lower index. We can also remove elements from a list. The pop method returns the item at a given index and deletes it from the list. Let's pop the element at index two. The resulting gap is filled by moving all the elements with higher indices, one position to the left. The element at index two is removed from the list and returned after the call to pop. So we could print both values. And I'm going to use an f string here as well. Element. And removed. The list became 2, 3, 5, 7, 11, 13. Note that the index parameter is optional. Calling the pop method without an index argument deletes and returns the last item in the list. So if I call primes dot pop, we get the last element removed, which is 13. The rest of the list remains unchanged. We still have the old elements, all the elements preceding the last value, which was 13. Now you shouldn't call pop on an empty list or with an invalid index because it will trigger an index error. We can also remove an item without returning it using the Remove list method. Unlike the pop method, which takes an index argument, remove expects a value, bear in mind that the value must be in the list or you will get a value error. Let me scroll up a bit and I call primes, remove five. Again, this takes a value and not an index. Now, since the value five is in the list, the call should succeed. Indeed, five is gone. The list elements get re-index, as in the case of calling pop. Now, these were the most common methods used to modify a list in Python, but you'll get to know more in the upcoming sections. 42. 7.5 Working with Tuples: Tuples are basically lists that you can't change or update after initializing them. In programming, we call such types immutable. To construct a tuple, we simply list the elements separated with commas. Now start VS code and create a new file called tapas dot p-y. Define your first tuple by typing the following code. The enclosing parenthesis is optional, but I prefer this style for better visual separation. Note that I used in closing parenthesis and not square brackets to declare the tuple. Square brackets are used to declare lists as described in the previous lessons. Now, the enclosing parenthesis are only required when declaring empty or single element tuples. So this is how you would declare an empty tuple or a single element tuple. A lot of what we covered for lists applies to us as well, except the methods used to modify their contents. We can't call pop, insert or append on a tuple. If you tried that, you'd get a syntax error. As you can see, the error says the tuple object has no attribute, append, neither pop or insert. However, we can access the elements of a tuple using the tuple at index syntax. Let's print the number at index two from the even number tuple. It's for. Indeed 0 has the index 02, has the index 14 is at index two. Now, can you tell me what gets printed after executing this line? You write it prints eight because that's the item at index 4. Now, what about this line? If you said it will produce an error, you are right. The highest index in the even numbers support is for. Hence, we'll get an index error. As a rule of thumb, use a tuple if you need a sequence of constant values that don't need to change, declare a list if you must modify or update its contents. Right? You've learned about the list and the tuple. But wait, there's another kind of sequence, as we'll see in a moment. 43. 7.6 Storing Key-Value Pairs: the Dictionary: Lists and tuples are great ways to structure ordered data. Python offers another built-in container type that dictionary. A dictionary lets us store key value pairs and it's the perfect data structure. If you need to look up values based on their identifier's, each value must be associated with a unique key. We can then use the key to access a particular value in the dictionary, but not the other way around. While the key needs to be unique, the values can be redundant. For example, the key could be the social security number and the value is the person's name. The Social Security Number 1, 2, 3, 4, 5, 6, 7, 8, 9 identifies a particular John Appleseed. However, there might be other persons with the same name but with different SSN. And one more thing, the order of keys and values is undefined in a dictionary. All right, let's write some code, start VS code and create a new file called dictionaries dot p-y. You can create an empty dictionary using the dict function. Try it out by typing the following statement in the code editor. Ssn, name pairs equals dict. The shorthand syntax for creating an empty dictionary uses two curly braces. So we get the same results. If we write the following, we can add key value pairs to a dictionary by writing the name of the dictionary, followed by the key between square brackets and assign the value using the equals sign. It's also possible to initialize the dictionary upon his declaration by putting the key value pairs between curly braces. Each key is separated from the value by a colon, and the key value pairs are separated by commas. And let's print out the contents of our dictionary. Now, the output might differ in your case, because dictionaries don't store their keys and values in order to retrieve the value associated with a key from a dictionary, use the syntax dictionary name followed by the key between square brackets. The following statement prints Pam Beasley to the terminal since her name is the value mapped to the given key. Now, what happens if we tried to use a key that's not in the dictionary? And I provide a key, let's say 999999, 99. Trying to access a value using an invalid key triggers an error of type II error. 44. 7.7 Modifying the Dictionary: Dictionaries can be modified regardless of the way we initialize them. In other words, we can add key value pairs or replace the value linked to a particular key. Use the following syntax to add a new key value pair. If the key already exists in the dictionary, the associated value gets updated with the new value. The statement updates the name Pam Beasley with Angela Martin for the key 000, 000, 000, 000, 000 three. However, if we use a new key, the key value pair gets added to the dictionary. We can also delete items from a dictionary using the del function. To identify the item to be deleted, we need to pass in the dictionary name followed by the specific key between square brackets. Let's delete to ICT. And Dwight's key is this. Let's borrow it from the dictionary, right? We're going to track the changes using print statements. Let's come on these out. So I put a print here. And let's print the contents of the dictionary after calling the delete function. Originally, we had a dictionary with four key value pairs. Then we deleted Dwight shrewd. And now we've got three key value pairs left. Dwight shrewd and his key are gone from the dictionary. Before calling down, make sure the key exists. Otherwise, you will get a key error. Let's change the key to something that's not in the dictionary. Now, run the program, and here's our key error. You can use the in keyword to check if a particular key exists in that dictionary. The following code snippet checks for the key before trying to delete the corresponding key value pair. If key in a dictionary, then we can call the lead safely. The key and the associated value gets deleted from the dictionary. Otherwise, we print a warning to the terminal. I use an f string to include the key, and we print invalid key and the value of the key. Now, this key doesn't exist in our dictionary, so we'll get a warning message. Let's change it to a valid key. Let's say 0, 0, 3. And now the key and the associated value was deleted successfully. All right, Let's wrap it up. The dictionary offers fast access to its elements through unique keys associated with each item. It is important to remember that the order of the store key value pairs is undefined. 45. 7.8 Iterating through Containers: Containers let us store and organize our data. You've learned so far that the list and the tuple store the values in a specific order. And we can access those values using their indices. The dictionary stores key value pairs, and it should be used to quickly access the data through the unique keys associated with each value. One of the most common tasks you will do with a list is to iterate through its elements. We can do that easily using the foreign statement. Start VS code and create a new file called looping through containers dot p-y. We start by creating a list of prime numbers. And here comes the for-in loop for number in primes. And now we print each number and we can see the result into terminal. Another possibility is to iterate through the list using a while loop. We need an index. We iterate while the index is smaller than the length of the list. And let's print each item by index. Finally, we increment the index in each iteration. Same result. Notice that I had to introduce an additional variable for keeping track of the index. We have to increment the index upon each iteration and check if it's still valid in the wireless statement. The Len function gives us how many elements there are in the primes list. We have five items in total, and the valid indices are in the range 0. Len primes minus1 bear in mind that indices start at 0. Thus, the fifth element has index four and not five, which is the length of the list. That's why we check if the index is less than the number of items in the list. If we go back to our for-in loop, you can see that it's much cleaner. We need no boundary checks or index housekeeping of any kind. Now we can do more useful things than just printing out the values as we loop through the items of a list. For example, we could check if a number is odd or even. I use the modulo operator. We've used it in a previous lecture. So it should be familiar. If the number is perfectly divisible by two, then it's an even number. Otherwise, we have an odd number. How about collecting the odd and even numbers in dedicated lists? I create two variables, two lists, even numbers, and initialize it to an empty list. And odd numbers. Another empty list. Now, if the number is even, instead of printing a message, we add it to the even numbers list. I use the append list method. And if it's an odd number I added to the odd numbers list, then we can use the for in loop to iterate through the even numbers and odd numbered lists. Two. We start with the even numbers for I in even numbers, print I. And then we print the odd numbers for j. In odd numbers, print j. Indeed, our list contains only one even number. That to all the others are odd numbers, 357 and 11. As you can see, the for-in loop has a clear intuitive syntax. It does the job without us having to know anything about the inner workings of the list. 46. 7.9 Iterating through Containers Part 2: Now, how about iterating through the elements of a dictionary? As you may recall, the dictionary doesn't store its elements in a predefined order. Therefore, iterating through the values of a dictionary doesn't make sense. However, we can retrieve all the keys or values of a dictionary using its keys or values methods. Type the following code in your editor. I create a variable called keys and assign it to SSM name pairs dot keys. This dictionary method returns are the keys as a set and same for values. And now we can write the foreign loops to iterate through the keys and the values. Dictionary keys first, four key in keys, print key. And the values for value in values, print value. And here you can see the output. Again, the order is undefined and it might be different when you run it, because at the dictionary stores its elements in an arbitrary order. There's also an items dictionary method that returns tuples of key value pairs. I create another variable called key value pairs and assign it the value SSN, name pairs, dot items. And now we can print the key value pairs. Print key value. Let's run it. And here are the key value pairs. Alternatively, you can write the for-in loop to retrieve a key value tuple directly upon each iteration. So here we have a tuple and I can print the key and the value separately. We'll explore containers more in the upcoming sections, but this will be enough to get you started. 47. 7.10 Demo: Extracting Duplicates: To solidify what you've learned will implement an application that relies on Python Containers. We start with a dictionary that contains a social security numbers as keys associated with names. Our task is to extract are the names that appear more than once and print them along with the Social Security numbers. Let's begin by creating a new file in VS code called Find Duplicates dot p-y. Next, define the following dictionary. Solving a challenge requires us to understand the task and the expected output. Note that the name Dwight shrewd appears only once, while John Appleseed is listed twice. And we've got three Pam Beasley names in the dictionary. We need to find the duplicate names and print them together with their SSN. The result should be in the following form. So we have the name and then the social security numbers. Since John Appleseed appears twice, we have two assassins. Pam appears three times the nth or dictionary. So we have three sss. Now to produce the expected output, we need to construct a dictionary that has the name as the key and the value should be a list of SSL. So we need the list in the form name, which is the key, and the social security numbers. Within a list. Again, a key and a list of Social Security numbers. Format requires a dictionary that holds lists as values. Luckily, Python and R, The other programming languages I know, let us construct containers that store other containers in them. Since you already know what a function is and how to define it, we incorporate the extraction of logic in the following function. I call the function find duplicate names, and it takes a single parameter of type Dictionary. The return type is also a dictionary. So this function takes the dictionary that holds the SSN name pairs as an input argument, returns the dictionary of name ssn list pairs. Now let's start implementing the functions body by creating an empty dictionary. Next, extract the values of the input dictionary using the values dictionary method. This call returns all the names in the dictionary. We need these names to find the duplicates. The values method returns a view that needs to be converted to a list using the list function. We convert the result of calling the values method on the dictionary to list. Now we'll iterate over the key value pairs of the input dictionary using a for-in loop. I use the items dictionary method to access the key value tuples, as discussed in the previous lesson. And now we check if the name appears multiple times in the dictionary. Here's where we need the names variable. Since we are interested in the duplicates, we check if the given name appears more than once in the list. And if we found a duplicate, we have to add the name as a new key to the result dictionary. The belonging SSN needs to be inserted in the list of SSMS. For the redundant name, I use the getMethod instead of using the key based access because the ladder would cause an error if the key doesn't exist. The key is the name. And that's a default value it should return, which is an empty list. And then we append the SSN to the list of SSN is mapped to the given name. And finally, we return the result. Now let's test the function. I create a variable duplicate name, ssn equals, and I call find duplicate names by passing in the SSN name pairs dictionary. I'm going to print the results using a for-in loop for name, SS ends In duplicate name ssn dot items will print a message using an f string found duplicate name, and the name with social security numbers and the list of SSL. Now let's see how it works. Excellent. It Found John Appleseed twice and Pam three times. Alright, and that's about containers for now. We'll work with containers also in the upcoming sections. But for now, you're good to go. 48. 8.1 Getting Ready for Errors: Even experienced programmers make mistakes. So it's normal that your code doesn't compile at first when you are a beginner, you may miss a column, skip an argument in a function call, or use the wrong indentation. These are common mistakes and Visual Studio Code and all the other modern IDEs will help you fix most of them. This session is not about syntax problems. Instead, we're going to talk about runtime errors, the issues that come up when running our code. We've seen such errors in our code examples so far, like type error, index error, and so on. We prevented these errors by implementing the required convergence and validating the indices before using them. As our programs become more sophisticated, it gets harder to detect subtle problems. The code may break in unexpected places, and it's natural to get frustrated. When that happens. You just invested time and effort into learning something new, but it doesn't work as expected. Hanging there. And I show you how to handle these nasty programming errors. Start by opening VS code and create a new file called errors dot p-y. Now type the following code. Z equals 10 divided by 0. And let's run it. It's a trivial mistake. We tried to divide a number by 0. Nobody makes such basic mistakes, right? But wait, the issues are not always that obvious in programming. Now, delete the line you just typed and checkout the following code. X equals ten. And now I have write a for-in loop for I in range 100 x minus 2, and let's print I, divide it by x. Can you spot the problem? If I run this snippet, I will get the same 0 division error as before. However, the problem isn't that evident as in the case of z equals 10 divided by 0. We need to analyze the code. And depending on our ability to detect logic problems, it may take some time to find the shoe. In the loop body, we keep dividing the value of i with x. As we iterate through the range, x gets smaller, and after five iterations, it becomes 0. Thus, we end up dividing by 0. Again. In worst-case is the issue remains uncovered and it causes your program to crash. Now add a print statement after the for loop and run the program. Again. The greeting doesn't get printed to the terminal. The line that triggered the arithmetic error causes your program to crash. Now, errors like this often arise in programming. That's why it's essential to prepare our code for exceptional situations. 49. 8.2 The Buggy Equation Solver: Exceptional handling allows us to handle unforeseen errors that can occur in spite of our best efforts to implement bug-free code. Now, imagine the following situation. You need to create a program to solve for x in eight times X plus B equals C. The user enters a, B, and C, and the program calculates the variable x. The math part is straightforward to calculate x, we use the following formula. Here's the explanation, just in case you were wondering how we arrived at the solution. First, subtract b from both sides of the equation. Since b minus b is 0, the equation becomes 8 times x equals c minus b. After dividing both sides by a, we get the formula that solves for x in eight times x plus b equals c. All right, now let's implement the program, open up VS code and create the file equations solver.py. Start with the solid equation function that calculates x using the formula above. It takes three parameters, a of type float, be also a float and see the same type and it returns a result of type float. And the implementation, we're converting the parameters to float using the built-in float function. We need to perform this conversion to ensure that we're using the right numeric type. Next, write the statements to let the user input the values for a, B, and C respectively. Let's start with message to show what we're doing. So we're trying to solve this equation. Ax plus B equals C, which is a linear equation. And now ask the user for all the three variables. And the code is similar. So I'm just going to grab Line 5 and copy paste it B and C. Finally, let's call the salt equation function to calculate x and then print the result. X equals some equation and I pass in the parameters a, b, and c. And let's print the result. I'm using an f string. The message is x is the value of x. Now run the program. For a, I entered 10, B. Let's make it three and see about five. So this is one possible outcome. Now, rerun the program and make sure you enter 0 for a, be three and C 42. We got an error. Although our code has no issues, we can't control what the user enters. There are different ways to solve this problem. One approach is to catch errors if they happen. The technique is commonly called exception or error handling in programming. 50. 8.3 Handling Errors: In this lecture, we're going to incorporate exception handling into the equation solver program. Python uses the try and except keywords to handle exceptions in some form. Try except error type. The except statement can catch multiple exceptions by listing the exceptions within parenthesis separated by commas. You will also encounter tri-state months with more than one except clause. This form is useful if your code may throw different exceptions and you want to handle them separately. The strategy is called structured exception handling. Now, let's go back to our equation solver. So here's our function. Instead of returning the result of c minus b divided by a directly, we're going to include exception handling using try. And except. I added the code that might throw 0 division error in the try clause. If the error occurs, we catch it and print a warning except 0 division error. And if it occurs, we print an error, message. Error a can't be 0. Enter a valid value. Now, if we execute this code, everything works as before. But there's a huge difference. You'll notice the benefits of exceptional handling when you enter the value 0 for a instead of crashing the program outputs on error message. And the last print statement is also executed. Although the value of x is undefined, That's why we see x is none. Now, let's rerun the program and enter some non-numeric characters. Cue for a, w, for B, and for C. In spite of our exception handling efforts, we got an error. This is something new. Value error is an error that we didn't handle. We can catch this new error type by adding it to the error is caught by the except statement. Now, I need to use parenthesis since we have multiple values. And I'm going to add value error to the list. Let's run the program again. Q for a, W4 be, and why for c? Now that we're handling multiple errors, we need to change the warning message to something more generic, like error. Enter a valid value. Sometimes it's a better idea to handle errors separately. Doing so allows us to implement specific logic. In our case, will emit a dedicated warning for each error type. So here we should tell that a can't be 0. And if we got a value error, that's a different thing. So lets the user know what the real issue. Make sure you enter numeric values. And now we should get different error messages. Let's test the first scenario. When we have 0 for a error can be 0. And now repeat for non-numeric values. So for a, I enter a for B, B for C, whatever. And now we've got the second message. So that's how we intercept and handle errors in Python. We talk about raising exceptions Next. 51. 8.4 Raising Exceptions: There are cases when we want to handle the error, but throw it further and let the color decide what to do next. The raise keyword allows us to rearrange an error. We'll continue working with the equation solver.py. So reopen it. If you haven't opened it already. Add the raise statement to the second except clause. Now run the app and enter invalid non-numeric values. We see the error message printed to the terminal, but the value error exception occurs two, to make it disappear, we need to handle the error also under colors side by embedding the x equals solve equation statement in a try clause. And we need the accept part 2. I print something bad happened. Note that except has no errors listed, which means that it catches all exceptions. That's a bad idea since we'll also catch exceptions that aren't actually errors that should be handled by user code instead of using a bear. Except a better approach is to catch all normal errors. That is, the errors meant to be intercepted by client code. These errors are represented by the exception type. So I'll put exception here. The try-except statement has an optional else clause. The else block gets executed if the try clause doesn't raise an exception. So let's add an S to our code. If everything went well, there was no exception. We print the value of x. Instead of having it here. The use of the else clause is recommended over adding additional code to the try clause. This approach avoids catching exceptions that aren't raised by the code protected by the try-except statement. We can use the raise statement to force a specific exception. For example, we could check the user input to prevent division by 0 issues early on. Insert this code right after retrieving the user input for the variable a. If float a is 0, we raise a value error. And you can provide a text explaining what the issue is. If the user enters 0 for a value error exception with the custom message gets raised, which in turn causes the program to crash instantly. There you go. 52. 8.5 Cleaning Up: the finally Keyword: There might be cases when we need to do some processing before leaving a function, regardless of whether an error occurs or not. Typically, this includes executing cleanup tasks, such as closing open files and releasing external resources. You can use the final keyword to run cleanup actions. Finally, keywords blood gets always executed before returning from the function, even if an exception gets raised. In the following example, I'm going to use finally to print a trace message. Let's remove the raise statement and add a finally block. Print leaving solve equation. Now, this message leaving sought equation will always appear in the terminal. Even if an exception occurs within the function. I need to remove these lines. And now let's rerun the program. Enter 0 for a, 12 for B, and 42 for C. So we've got the error message a can't be 0, enter a valid value, but also the leaving solve equation trace message will see a practical example of implementing cleanup actions in the file input and output section. 53. 9.1 Working with Files: Reading data from a file or saving files to the hard drive. Our everyday tasks in programming, a file is a collection of data that's persisted on the storage medium, such as the computer's hard drive. The type of data contained in a file can vary. We have text files, but there are also files containing binary data like programs and images. A file is identified by a folder path, which is the files folder location in the file system, a name, the actual name of the file, and an extension that indicates the type of data stored in a given file, such as dot PY for Python files, dot TXT, for text files, dot PNG for image files and so on. Python makes it easy to work with fires. However, there are a couple of things to watch out for when it comes to file input and output. Let's start with the requirement of reading data from a file. To access the files data, we need to know its path. Then we try to open the file for reading. I said we try because our attempt my fail for various reasons. File may not exist or it could be open already. The data it contains might be in a different format than we expected, for example, binary versus text. Now, if none of these errors happen, we read and process the file's contents. And finally, we need to close it. It's imperative to close the file when we're done with it, or you will get strange problems in your programs. Here's a simplified activity diagram showing the decisions involved in the process of opening a file and reading its contents. There may be even more conditional logic required when working with files, since so many things can go wrong. The bottom line, file input and output, requires us to be prepared for various errors. Now, let's see how to read and write files in Python. 54. 9.2 Writing Text to a File: In this lesson, we're going to implement a program that rise text to a file, create a new file in VS code and name it file right dot p-y. To write to a file, we must first open it. Once the file is open, we can write data into it. When we're done with the writing, we need to close the file. Let's embed all these steps into a function with the following signature. I call it right file. And it has a file path parameter of type string. And the text that should go into the file. The return type is an integer. The right file function takes two parameters. File path identifies the file in the file system, and texts, which is the text we want to write into this file. The function returns an integer that represents the number of characters written into the file. To open the file at the provided path, we use the built-in open function, which takes several parameters, but we'll only use two, the path to the file to open and the mode in which the file is opened. The default mode is to open the file for reading in text mode. We can provide the modes using ladders. Here's the list of mode values and they are meaning, if we don't provide the mode argument, the file opens for reading in text mode by default. But we're going to provide this parameter and we'll be using w for riding. Since we want to write to this file, the open function returns a file handle upon success. So let's declare this handle first and initialize it to none, which denotes an empty initial state. As we saw in the previous lesson, opening a file may fail for various reasons. The open function raises OS error upon failure. Thus, we call it from a try clause and use the returns a handle to write the text to the file. Next, we pass the text to the right method. Now I use the return handled to write the text to the file. The write method returns the number of Britain bytes. We're going to return this value to the color. Next, we need to catch the OS error exception and print an error message if it occurs. Except OS error. Let's print. I use an f string, which allows us to also include the file path in the error message. Couldn't open file path. And the value of the file path. We're almost done. Let's not forget to close the file. We could add the missing statement in the try clause. However, if an exception occurs in the middle of our code, the file remains open. To make sure this code always executes, we need to put it in the finally clause. If the file handle is not none, we call File Close. As an extra precaution, we check if the file handle is valid. If opening the file failed, the file handle kept its initial value, which is none. Calling close on an invalid handle would raise an exception. So it's a good idea to validate the file handle. The function is ready. All right, now let's use our freshly implemented function. First, create a variable that holds the FIS name. Then called the right file function and store the returned value, which is the number of characters written to the file in the count variable. Count equals right file. And I provide the filename and the text. How about Hello, Python? If the cost succeeds, we print the number of characters to the terminal. Otherwise, we print a warning message. If count is not none, print the value of the count variable. Characters written to filename. Else. Print couldn't write to file and the file name. Now run the program. A file called file.txt should be created. Since we pass the name of a file without the file path, the file gets created in the same folder in which you are running the program. If you don't see the file where you expected it to be created, your program may be running in a different folder to check where your script is running at the following statements and check the bath printed in the terminal after executing your program. Import OS, print OS dot path, dot absolute path, and retrieve the current working directory, which in my case is the root folder. Excellent. Now you know how to write texts to a file. Next, we're going to implement a program that reads the contents of this file. 55. 9.3 Reading Text from a File: We've seen how to write text to a file. Now let's write a program to read the contents of a file. Open VS Code, create a new file and save it as FileReader dot p-y. We start by creating a function called read file. Function takes a file path parameter that identifies the file in the file system of type string. And it returns an array of strings that represent the text lines in the file. We declare the handler and initialize it to none. Will use the open function to open the file as we did in the previous lesson. However, we don't provide the mode argument. Thus, the default mode applies, which opens the file for reading in text mode. As we've discussed, the open function may raise an exception. Therefore, it is necessary to embed it in a try clause. If an OS error occurs, we print an error message. Print error couldn't open the file path. And the value of the file path argument. The actual reading of the text lines happens in the try-except statements as Clause, as discussed in the error handling lesson, the else block gets executed if the try clause doesn't raise an exception. That means that the statements in the else block will only run if the file could be opened successfully. Python makes it very easy to read the text file. We can use a for-in loop to read the lines of text. Each line is then added to the list. And when the loop finishes, we return the list to the color. I initialize the lines variable with an empty list. And now the for loop. For line in file. I use the list append method. I appended the line of text that was read from the file. And finally, we return the list. Let's not forget to close the file in the finally block as usual. First, validate the handle. If it's not none, meaning that it was opened, then let's close it. We can try it out right away. Car the read file function and assign the return value to the text variable. And let's print the returned list with the text lines to the terminal. If text is not, none, let's print it. If everything went well, you should see this output. You might get an error message instead saying error couldn't open the file path, my file.txt. This message appears if my file.txt has not been created. If you ran the previous sections demo successfully, the file should exist in the folder from where you are running the program. If that's not the case, load the file writer dot PY file and run it once. Congrats, you've just learned that the basics of file input and output using Python. In the next section, we'll be digging into more abstract topics. 56. 10.1 What's Object Orientation?: We did pretty well so far without object orientation. So what's all the fuss about it? To understand the importance of object-oriented programming, we need to go back a few decades and see how things evolved. In the stone age of programming, there were no fancy IDs or text editors. Actually, programs were written way before the days of displays. Programmers coded their programs on special sheets of paper called coding sheets. The following example shows a cobol coding sheet. I'm not kidding. That's how programmers wrote their code. Until the mid 1970s. The sheets were taken by operators whose job was to punch you the instructions into a punched guard using a key punch machine. If the operator made a single mistake, the entire God had to be republished. Later, the punchcards were converted to magnetic type files that could be stored more effectively. Initially, computer programs were big, contiguous chunks of code. Unstructured programming was the earliest programming paradigm. The code consisted of sequentially ordered instructions. Each statement would go in a new line. Source code lines were numbered or identified by a label. Here's a snippet in Sinclair basic that converts from Fahrenheit to Celsius degrees. As the programs grow in complexity, the drawbacks of this approach had become apparent. Maintaining or even understanding such a code-base was challenging. To make any changes or improvements, you had to check the statement line by line. This desk becomes overwhelming as the number of code lines increases. Non-structured programming has received much criticism for producing hardly readable so called spaghetti code. The term spaghetti code is a pejorative description for complicated, difficult to understand, and impossible to maintain software. Structured programming emerged in the late fifties. Structured programming languages breakdown code into logical steps. They rely on subroutines or functions which contain a set of instructions to be carried out. By now you should be familiar with these concepts since we've implemented and used functions in the previous lectures. Structured programming was a significant improvement compared to the monolithic coding practices. The introduction of named functions improves the readability of the computer programs and reduce development time substantially. Even with the improved quality, developers started to face new challenges as the programs became more sophisticated, structured programming could not address the increased complexity. Object-orientation appeared in the 1980s. It was the next big step in the evolution of the programming paradigms. Object-orientation aims to bring the world of programming closer to the real world. The main idea was to split apart the program into self-contained objects. Each object represents a part of the system that gets mapped to a distinct entity. An object functions as a separate program by itself. It operates on its own data and has a specific role. The objects that formed the system interact with each other. Let's talk about objects next. 57. 10.2 Understanding Objects: Object-oriented programming is organized around self-contained objects. Now, that might sound vague at first, but it's really about the way we think about designing our programs. It requires a mental shift compared to focusing solely on functions. However, once you get used to this new way of thinking, you'll notice that it becomes easier to build sophisticated applications. All right, let's introduce the main ideas around object-orientation. We start with the object. An object represents a thing. Each object encapsulates its own data and logic. Objects interact with each other to make our programs work. An object can be simple or complex. Depending on the level of granularity we need to accomplish a specific functionality. We could model a rectangle as an object, but we might consider a space station on object to the way we define our objects depends on the level of detail needed to solve a particular problem. Sometimes a higher level of abstraction, we're Sufis. We could say this object represents a person who has a name and a social security number without considering details like the person's height, weight, or hair color. In other cases, we need to be more specific. We can describe an object using its properties, such as its name, color, size, or shape. Let's consider a car. We can choose between petrol, diesel, electric, or hybrid engines. Most cars come with a basic solid color, such as white, black, gray, or silver. But we can have metallic or matte finishes to the cars color and the engine type are fixed properties. While other attributes, such as the car's position or speed can change, we can describe an object in the real world using its properties. Like the car's name is Tesla Model S. Its top speed is 155 miles per hour. Color, mid night silver metallic. This approach also works in an object-oriented language. Objects have their identity, their own state. Changing the state of an object doesn't change the state of other objects. If we start a car, it won't affect all the other vehicles. Their state is independent and each has its private identity. Besides properties and identity, an object has its own behavior. The behavior of an object is what it can do. The black car starts. In this sentence, we identify one object. The car start is the behavior or the action performed by the car object. And black is its color, one of its attributes. We can identify the object quickly since it's the noun in the sentence. The verb is the behavior, and the adjective is the property. So black is a property. The car is the object and starts is the behavior. The idea of describing an object using its properties, identity, and behavior is pretty straight forward. But how can we apply this approach to actual code? Not so quick. We need to introduce the concept of the class first. 58. 10.3 Introducing the Class: The creation of object-oriented system starts by identifying the required objects. The objects in our programs represent things like cars, person's files, databases. In the object-oriented world, we need to have a class before we can create an object. The class is the blueprint of an object. You can think of a class as a plan, a description of an object. A concrete object is a realization of this blueprint. Let's say you want to use a Pokemon in your program. A class called Pokemon would provide a blueprint for what the Pokemon looks like and what it can do. All right, We've had enough theory. It's time to switch to coding, open VS code and create a new file called class dot p-y. In Python, we create a class using the class keyword followed by the name of the class in the upper CamelCase style. Next, we define three instance variables that represent the Pokemon, name, armor, level, and hit points. In Python, instance variables are defined within methods. Bear in mind that most object-oriented programming languages use a different approach to declaring instance variables, but that's how Python works. Alright? We're going to define the name armor and hitpoints instance variables within the init method. In it, also referred to as a constructor, is a special method that gets executed whenever we initialize a Pokemon object. You should never call a classes init method directly. In Python, leading and trailing double underscores indicate a variable or a method that's not meant to be used directly. We'll talk about private access later in this section. Now, Python requires us to specify self as the first parameter of each instance method. Self is the new object graded when we instantiate a class and it gets passed to the initializer. Most modern programming languages past self as a hidden parameter to instance methods, but Python decided to make it explicit. The self.age variable name syntax means that we're accessing instance variables of the Pokemon object, setting them using self.name, self.age, armor, and Safdar hitpoints makes them accessible for the lifetime of the object. This class does us that each object that gets created has a name, armor level and hit points. It doesn't say what the name or the armor level is. We initialize these properties during instantiation to create a new instance, type the class name followed by the argument lists around it by parenthesis. Let's create one instance. I call it Pikachu. I provide Pikachu for name 100, max armor level, and max hit 1, 0, 0, 0, 0, 0. Now let's define some behavior. Pokemons can attack and defend themselves. So add the attack and the defend method. Instance methods are defined the same way as functions, except that we need to pass in self as the first parameter. And let's print the object's name. And now let's define the defend method two. And again, we print a message to the terminal. To use an instance method, we need an object of that class first. Then we can call the method using the dot syntax. Since we have an object, we can call the methods right away. Let's call attack and say attack again. And now it defends itself. All right, now let's give it a try. And here in the terminal, we can see the result of executing the program. We define the class by giving it a name, Pokemon, declaring its instance variables, name, armor, and hit points. And the methods attack and defend. The Pokemon class lets us create as many objects as needed. We could create another object, say snot lags. I provide its name, max armor and max hit and it attacks. And the third object, charm under the name, again, Max armor and hit points. And I can call any of its methods, say defend. Another big benefit of classes is that we can reuse them. We've already used many built-in types, including the string, the list, that dictionary, and the various numeric types. Instead of re-implementing the functionality provided by these types, we could focus on creating our programs. We covered the object and the class. Next, we'll take a look at the core object orientation principles. 59. 10.4 Abstraction: Abstraction is a way of describing complex problems in simple terms by ignoring some details, eliminating the nitty-gritty details, let us focus on the bigger picture. We can dig deeper once we have a broader understanding. If I say cat, you know what I'm talking about? Instantly, I don't need to specify that it's a small for a male version kitten, unless these additional details have relevance to the story. We are naturally good at generalizing things. We skip the irrelevant details, but people can still understand us. That's because our brains are wired to understand abstract ideas like cat, house or car. Abstraction works the same way in the object-oriented world. When we start defining a class, we focus on the essential qualities of that class and discard the unimportant ones. In our Pokemon example, we started with the essential attributes and methods. We don't need details like age, weight, or height. These attributes are an essential in our current application. That's how abstraction works. We focused on what's important and ignore all the details we don't need. 60. 10.5 Encapsulation and Data Hiding: The next fundamental idea to keep in mind when dealing with object-orientation is called encapsulation. We encapsulate something to protect it and keep its parts together. In object-orientation, encapsulation translates to packing together variables and functions in a class. Encapsulation also means hiding the internal details that shouldn't be used by callers. We can use a phone without understanding how the touchscreen, the camera, or the logic board works. Similarly, we don't want to expose the inner workings of our class. An object should only reveal the essential features. This concept is called data hiding. By hiding its internal details, we protect if the object from external interference. Other programming languages let us hide the properties and the methods by making them private. Private variables and methods can only be used within the class that defines them, but can't be accessed from the outside. Python doesn't have a private keyword. All class instance variables and methods are public. Instead of using a special keyword, Python relies on naming conventions. If a variable or method shouldn't be accessed from the outside, we precede its name with an underscore r. Right? Now let's switch over to VS code. We're going to add the property and the method to the Pokemon class. We add the East charging private property first. Next, I define a private method. Now since is charging and change attacks start with an underscore. They are considered private. And let's copy over the print statement and make some changes. Is charging is a private property and change attack is a private method. In other words, they are not meant to be used by clients. Note that you can still access the East charging variable or call the change attack method on the poll came on object. Although you won't get any warnings or errors, python developers know that using variables or methods that start with an underscore is a bad idea. Since these are private, their behavior may change or they might even be deleted over time. Hiding certain properties or methods prevents clients from modifying the object in ways we did not originally plan, whether it's intentional or accidental. Additionally, we prevent other parts of the system from relying on properties or behavior that may change. Data hiding is not about selfishly keeping stuff for ourselves. It's rather about protecting our classes from unwanted external dependencies. If we expose unnecessary details, any changes to those attributes or methods may affect other parts of the system. Whereas if we restrict access to that data or behavior, we don't have to worry about the ripple effect of our changes. As a rule of thumb, expose only as much of your class properties and methods as needed for normal usage. Data hiding plays an essential role in reducing the dependencies between objects. A tightly coupled system with most of the objects depending on each other, is the unmistakable signs of a bad design. Updating or maintaining such a system is a pain. Any tiny modification cascades down and requires you to change other parts of the system to its like a never-ending nightmare. Object-oriented programming principles are here to make our lives easier. Next up is the idea of inheritance. 61. 10.6 Inheritance: Inheritance is a key concept in object-oriented programming. Without inheritance would end up writing similar code over and over again. Inheritance means code reuse. That is, reusing an existing class since implementation in new classes. Let us start with an example. We modeled the Pokemon class with the main properties and behavior in mind. Given this class, we were able to create our Pokemon instances. Now, what if we need new types, like electric water or flying Pokemon? We need new classes. Since these new types have special abilities, the Pokemon class has, the property is name, armor and hitpoints, and it can attack and defend itself. The electric, water and flying Pokemon does have all these properties and they are able to attack and defend themselves to. Additionally, they also have specialized functionality. And electric Pokemon has the ability to wild charge. This attack is only available to electric type. Okay, months. At what tail is a damaging water Pokemon move and flying Pokemon scan performed the dragon ascent attack. As you've probably realized, the three new classes are almost identical to the Pokemon class. The only difference is the special attack type. We could add the new methods to the Pokemon class. If we did that with end up in a class that has too many responsibilities. Suddenly all Pokemon objects could swim and fly and discharge electricity. Now, that doesn't sound like a particularly good idea. Our classes should be simple. They need to have a well-defined purpose. Object orientation is about granularity and separation of concerns. Each class should focus on one set of specific functionality and do that well, grading one size fits all monolithic classes is a major mistake in object-oriented software development. So how about keeping these classes separate? Now, only electric Pokemon objects can discharge electricity. Water Pokemons can employ the aqua tail attack. And flying Pokemons are capable of performing a dragon ascend. Great, however, we're now facing another issue. We keep repeating the same code for the shared functionality. Object-oriented programming languages have a solution for this kind of problem. The solution is called inheritance. In Python, a class can inherit all the variables and methods from another class using the following syntax. Now, child class has the same properties and methods as parent class. Alright, let's make electric Pokemon, water Pokemon, and flying Pokemon inherit from the Pokemon class. In object-oriented terms, Pokemon is called the base parent or superclass. Whereas the electric Pokemon, water Pokemon, and flying Pokemon are subclasses or child classes. The data and the behavior from the Pokemon class become available to all its subclasses. And we only had to add the specialized methods to the Pokemon subclasses. If we enhance or modify the Pokemon class, the subclasses will automatically receive those changes to. Inheritance is a powerful idea which can save us from a lot of typing. Besides, it paves the road to another handy feature called polymorphism. But first, let's talk about method overriding. 62. 10.7 Method Overriding: The electric, water and flying Pokemon all inherit the properties and the behavior of their Pokemon superclass. So they have a name, armor, hitpoints, and they can attack and defend themselves. The water Pokemon inherits the attack method from the Pokemon superclass. Now, what if we need water Pokemon types to cause more damage than basic Pokemon instances? For that, we need to provide a specialized implementation of the attack method in the water Pokemon class. Changing the behavior of a method inherited from a parent class in one of its child classes is called method overriding. By overriding a method of the superclass, we tell that we want a different behavior in our child class than the one we inherited. Method overriding is straight forward. We re-implement the method with the same name and parameters as the one defined in the parent class and provide our own behavior. By doing so, our water Pokemon objects have a different attack behavior than they are Pokemon superclass. Calling the attack method on the electric Pokemon and flying Pokemon objects use the logic implemented in their superclass, since we didn't override the attack method in their case. Now, let's assume that we need a new speed instance variable in the water Pokemon class. We could override the init method and add a new parameter to initialize the variable. When we override a method, the superclasses method will no longer be called. We need to explicitly call the parents method if we want it to execute. So let's call the parent's init method to initialize are the instance variables defined in the base class. And then initialize the new water Pokemon speed instance variable to. After this change, we need to add an additional argument when creating water Pokemon objects. 63. 10.8 Polymorphism: Polymorphism is another term you will often hear when it comes to object-orientation. The word has Greek origins, and it consists of two words, polis, which means many, match and more fee, meaning form or shape. If you look up the word polymorphism, you will find the following definition. The condition of occurring in several different forms. Now, how does this apply to programming? Polymorphism lets us work with objects created from the Pokemon superclass or any of its subclasses. We don't need to know whether it's an electric Pokemon, water Pokemon, or flying Pokemon instance, to call any of the common methods defined in the superclass, we could create an army of mixed Pokemons and tell them to attack at once. The following step, it creates instances of different Pokemon classes. Then we create a tuple that contains the Pokemon instances. And finally, we can iterate through the items in the tuple and call their attack method without knowing their concrete type. The objects into Pokemons list are all instances of the Pokemon type or one of its subclasses. And that's all we know. Polymorphism is about working freely with instances of many different classes that share a common superclass. 64. 11.1 The Importance of Algorithms: If you continue coding sooner or later, you're going to encounter the term algorithm. In essence, an algorithm is a sequence of steps describing what the computer should do to solve a particular problem. Algorithms are essentially in computer science and are basically everywhere, even if you haven't noticed them yet. Your GPS uses route finding algorithms. Youtube relies on audio and video compression algorithms to play high-definition videos flawlessly. The amazing 3D graphics in games are possible thanks to sophisticated rendering algorithms. Computer algorithms have been developed and refined over the last couple of decades. The study of algorithms is essential to any programmer who wants to get past the basic Hello World beginner applications. We can't avoid algorithms when building complex systems that need to manage large amounts of data or solve complex problems efficiently. Besides, algorithm related questions will pop up during job interviews. So it's not a bad idea to know what algorithms are and how they can be applied to write more efficient code. By definition, algorithmic thinking is the ability to approach a problem and find the most efficient technique to solve it. Next, I'm going to show you the difference between a simple, un-optimized example and one that relies on a better proven algorithm. 65. 11.2 The Problem with Naive Implementations: To demonstrate the importance of algorithms, we're going to solve the same problem using two different approaches. The problem we're about to solve is the following. Implement a function that calculates the sum of the first n natural numbers. All right, let's open up VS code and create a new file called sum n dot p-y. Now declare a function called sum, which takes a single parameter. This parameter represents the number of natural numbers whose sum we want to calculate. The function returns an integer which gives the sum. The logic of our function is straightforward. It sums up all the numbers starting with 0 up to the value of the input parameter n. First, I initialize a variable called result. Then I use a for-in loop to calculate the result. So we iterate through the range of numbers, starting with 0 up to n. The plus equals operator keeps adding the number I to the result. And finally, we return it. Now we can try out our function. I create a variable, let's call it sum three equals. And I call the function and pass in the number three. And let's print the return value. Alright, now run the demo. The result is six, which is correct since one plus two plus three is six. The sum function relies on a for-in loop to calculate the result. The value of n determines the number of iterations. That means that the time to execute the same function increases with the input argument. And we can prove this by measuring the execution time. We're going to rely on the time Python module that provides functions to measure elapsed time. Now what's a module? A module is a file consisting of Python code and can include functions, classes, and variable definitions. To use a Python module, we need to import it. So let's insert a new empty line at line number one in the editor and add the following statement to import the time module. Next, insert a new line right after the sum functions definition. We need to cause some with steadily increasing values for n. So let's define a tuple called ranges with the values 10, 00, 00, 00, 00, 00, 10, and 100000. Then we cause some inner loop using the values from the arranges tuple. I'm going to remove this part. And instead, let's implement our for-in loop for n in ranges. And cause some with the value n. Again, n comes from the ranges. Tuple will rely on the process time ns function to keep track of the elapsed time, we need to sample at a time before and after calling some to measure the time required to execute the function, I create a variable called start. And let's fetch at the time. This function is very accurate, it returns the time in nanoseconds. Next, I create another variable called end and call process time ns, again to initialize it. Finally, all we need is to calculate the elapsed time and print the values. The execution time is represented by the variable x at time. And it's simply the difference between end and start. And let's print the value. I'm using an f string, the value of n. And as the execution time is, the value of x at time in nanoseconds. Now run the program. And here's the output. Your values may be slightly different, but the trend is clear. The execution time increases linearly with the input. Next, we're going to implement a more efficient solution using the formula that's more than 2 thousand years old. 66. 11.3 Applying a 2000-year-old Formula: The previous lectures code successfully computed the sum of the first n natural numbers. However, a working solution doesn't always mean that we found the optimal way to solve a particular problem. Our tests revealed that are functions performance deteriorates as the input gets bigger. Carl Friedrich Gauss is said to have found a better way to calculate sum n In his early youth, in the late 17 hundreds, Gauss was only an elementary student. The amazed his teacher with how quickly he found the sum of the integers from one to 100 to be 5050. Gauss recognized he had 50 pairs of numbers when he added the first and the last number in the series, the second and the second last number in the series, and so on. That can be expressed using the following formula, known as the triangular numbers for nulla. Sum n equals n times n plus one divided by two. Gauss was probably not the first to discover this formula. Likely its origin goes back to the Pythagoreans. And it was known as early as the sixth century before Christ. All right, given this formula, we can implement an improved version of the sum function. I create a new function and call it some optimized. It takes the argument of type int and returns an integer just like its sibling. Now, instead of applying a for-in loop, I'm going to apply the triangle numbers formula. So we return n times n plus 1 divided by 2. The sum optimized function is not only shorter. Matisse execution time doesn't depend on the input size. Let's run the same tests as we did for the sum function. I'm going to copy the for-in loop and paste it here. And we call the sum optimized function. In this case. Let's print what we're doing. I print a message for the sum optimized part in a new line, and also for our original measurement here. And let's also change the f string in the second case. Now, let's run our program. And here are the numbers. The results show that the execution times for the sum optimized function do not vary regardless of the input size. There are only some minor negligible differences in the range of microseconds. Besides, some optimized is more efficient even for smaller values. Some optimized, unlike the sum function, doesn't depend on the input size. By applying a smart 2000 year-old formula, we manage to implement a solution with optimal performance. Hope you've got a taste of what algorithms can do for your codes elegance and speed. Finding the optimal approach requires more analysis for sure. But the results are definitely paying off.