Transcript for:
Python Programming Course Overview

this course from Harvard University is an introduction to programming using the Python programming language you will learn how to read and write code as well as how to test and debug it this course is taught by Dr David Meen and it's designed for students with or without prior programming experience who'd like to Learn Python [Music] [Music] hello world my name is David Meen and this is cs50's Introduction to programming with python whereas cs50 itself is an introduction to the intellectual Enterprises of computer science and the Arts of programming this course is specifically focused on programming in Python itself at the beginning of the course will'll be focus on a topic in programming known as functions and variables mechanisms via which you can write code that solve smaller problems but you can compose those smaller Solutions into solutions to larger problems still we'll then transition to a look at conditionals a way in code of expressing yourself logically to maybe do something if some question has an answer of true or not do something if the answer is false we'll transition thereafter to introducing you to Loops the ability and code to do something again and again and again some number of times we then transition to something a little more technical known as exceptions unfortunately a lot can go wrong when you're writing code some of it your fault some of it perhaps someone else's fault but you can write code defensively so to speak and actually catch those kinds of exceptions those errors and handle them properly so that the users you're writing code for don't actually see the same thereafter we'll take a look at libraries third-party code written by other people often or perhaps yourself in the past that you can use and reuse in your own project so as to avoid Reinventing the wheel again and again we'll look thereafter at something called Unit tests and turns out you'll actually write code to test your own code but you won't have to write tests for your tests indeed this is a best practice in Industry writing tests for your code so that one you can be sure that your code today is hopefully if your tests are correct correct itself but moreover if you or someone else modifies your code tomorrow or down the line you can rerun those same tests to ensure that those new changes have not broken anything about your own code we'll then take a look at something called file Io Io for input and output the ability to not just store information inside of a computer's memory but rather save it persistently to diss so to speak to files and folders we'll then take a look at another technique known as regular expressions whereby in Python you can Define patterns and you can validate data to make sure the human type something in as you expect you can use regular Expressions to extract data perhaps from some data set you're trying to analyze we'll then take a look ultimately at objectoriented programming a paradigm a way of writing code whereby you can represent in code real world entities and this is in addition to other paradigms of programming that we'll also explore among them procedural programming where you write lots of those functions procedures really top to bottom to solve problems step by step and even something known as functional programming as well and then at the very end of the course will we equip you with all the more tools for your toolkit an additional uh building blocks additional vocabulary via which after this same course you can go off on your own and either take other courses or solve projects of your own using all of these mechanisms now this course itself assumes no prior programming background so you don't have to have written a single line of code in python or any language yet but this is also a course that you can take before during or even after cs50 itself if you'd like to get all the more versed with python each week via the course's lectures will we introduce you to any number of Concepts that will then drill down more deeply into in the form of problem sets each week that is programming projects that will enable you to apply some of those Lessons Learned to problems of your very own and by the end of the course you'll solve to have solved so many problems that ideally are representative of problems you'll eventually encounter in the real world whether you aspire to solve code in the technical world or perhaps in the Arts the humanities the social sciences the Natural Sciences or Beyond you'll have ultimately the vocabulary and the technical skills via which to approach the same this then is cs50 and this is cs50's Introduction to programming with python [Music] all right this is cs50's Introduction to programming with python my name is David men and this is our week on functions and variables but odds are many of you most of you have never actually programmed before so let's start by doing just that let me go ahead here and open up my computer and on it a program called Visual Studio code or VSS code which is just a very popular program nowadays for actually writing code now you don't have to write code using this particular tool in fact all we need at the end of the day is is a a so-called text editor a program for writing text and Heck if you really want you could even use something like Google Docs or Microsoft Word you'd have to save it in the right format but really at the end of the day all you need is a program for writing text because that's what code is text now within this particular program I'm going to have the ability to create one or more files via this top portion of the screen and I'm going to do so by diving right in and doing this at the bottom of my screen at the bottom of my screen is a so-called terminal window and this is a command line interface or CLI interface to the underlying computer be it your Mac or your PC or even some server in the cloud and what I'm going to do here is literally write code and then the name of the file that I want to code for instance hello.py as we'll soon see any program that you write in Python generally has a file name that ends inp to indicate to the computer that it's indeed a program written in Python now you'll see here at the top of my screen I have a blinking cursor a line one which is where the very first line of my code is going to and then just a tab that reminds me of the name of this file hello.py and without even knowing much python I'm going to write my very first program here as follows print open parenthesis quote hello comma World close quote and close parenthesis and you'll see that at my keyboard some of my thoughts were finished for me I only had to type one parenthesis and the other one automatically appeared and that's just a feature that we'll see of tools like this tool here now even if you've never programmed before odds already you can guess infer what this simple program is going to do and it's only one line print open parenthesis quote Hello World close quote close parenthesis indeed when I run this program ultimately it's just going to say hello to the world and in fact this is a very famous perhaps the most canonical program that you can write as your very first program in Python or any other language and so that's what I've done here but on my Mac my PC even my phone I'm generally in the habit like you of running programs by double clicking an icon or just tapping on the screen but I see no such icons here and in fact that's because my interface to at least my current Mac or PC or some server in the cloud is again only a CLI command line interface which even though it might feel like it's a step back from the menus and buttons and icons that you and I take for granted every day you'll find we think that it's ultimately a much more powerful interface and Incredibly popular to use among programmers in the real world so to run this program I'm going to have to use a command and I'm going to move my cursor back down to the bottom of the screen here where previously I already ran one command the command code which has the effect of opening vs code in my computer and then I passed in the name of the file that I wanted to code up now I have a chance to type a second command and you'll see I see a second dollar sign now the dollar sign here doesn't indicate any kind of currency or money it just is the symbol that's generally used to indicate your prompt where the command line interface wants you to put those commands now the command I can run here is going to be this I'm going to run python of hello.py now why is that well it turns out that when I actually write code in a language like python it's of course stored in that file hello.py but I need to interpret the code top to bottom left to right so that the computer knows what to do indeed at the end of the day even if you don't really know much about computers you've probably heard that computers only understand zeros and one the so-called binary system well if that's the case then something that says print and parenthe is and quote unquote hello world is not surely zeros and ones we have to somehow translate it into the zeros and ones that the computer understands now fortunately so long as you've installed such a program in advance there's a program as well as a language called python so python is not only a language in which we're going to write code it's also a program Otherwise Known As an interpreter that you install for free on your own Mac or PC or some server in the cloud and you can then run that program that interpreter passing to it as input the name of your file like mine here hello.py and then that program that interpreter will handle the process of reading it top to bottom left to right and translating it effectively into those zeros and ones that the computer can understand so let's do just that let me go back to vs code here I already typed out python of hello.py but I didn't get hit enter and that's what's now going to kick off this command and hopefully if I didn't mess any of this up I should see my very first program's output to the screen and voila hello world so if you two have typed exactly that same code and have executed exactly that same command you will have written your very first program in this case in Python well now let's take a step back and consider what is it that we actually just did and what is it we're looking here on the screen well first and foremost in most any programming language you tend to have access to what are called functions a function is like an action or a verb that lets you do something in the program and generally speaking any language comes with some predetermined set of functions some very basic actions or verbs that the computer will already know how to do for you that the language really will know how to do for you and you the programmer the human can use those functions at will to get the computer to do those things now the program in question here hello.py is using one function and you can perhaps guess what it is that function is of course going to be this function print and that print function of course doesn't print some pre-ordained string of text that is to say it prints whatever it is you want it to print and here too do we have another piece of terminology in the world of programming namely arguments an argument is an input to a function that somehow influences Its Behavior the people who invented python of course didn't necessarily know what it is you and I are going to want to print to the screen so they designed this print function using these parentheses with the ability to take as input some string of text be it in English or any other human language that is what you want this function ultimately to print onto the screen and what is it that the program's ultimately doing on the screen well it's printing of course it's showing us hello world on the screen and that's generally in programming known as a side effect it can be visual it can be audio in this case it's something that appears on the screen and functions therefore can indeed have these side effects one of the things they can do as this verb or action is to display on the screen as a side effect something like those World words that we wanted hello world so that's my first program and you know I'm feeling pretty good everything worked as planned I didn't make any mistakes but honestly when you're learning how to program and even once you've learned how to program years later you're going to make mistakes and those mistakes of course are refer to a term you might already know which is that of a bug a bug is a mistake in a program and they can take so many forms and take comfort perhaps in knowing that over the coming weeks you're going to make so many mistakes you're going to have so many bugs in your code just like I did and just as I still do and those bugs themselves are just mistakes that are problems for you to solve and over the weeks to come we're going to give you a lot of tools both mental and Technical via which you can solve those problems but just don't get discouraged if when writing your program for the first time it doesn't even work that first time it will with time with practice and with experience so let me deliberately now make a mistake that there was a nonzero chance I might have done accidentally already but I got lucky let me go ahead and just suppose I forgot to include something like the closing parenthesis at the end of this line of code you know the code is almost correct it's like 99% of the way there but now that I've pointed it out it's pretty obvious that it's missing that closed parenthesis but even little seemingly Minor Details like that that you and I as humans wouldn't really care about and if you're sending an email or a text message oh whatever it's just a typo it's not that big a deal it is going to be a big deal to the computer a computer is going to take you literally and if you don't finish your thought in the the way the language expects it's not going to necessarily run at all so let's do this I'm going to go ahead here and clear my screen down at the bottom just so I can start fresh and I'm going to go ahead and run this version of my program after having made that change by deleting the parenthesis I'm going to go ahead and type python again of hello.py and this time when I hit enter I'm hoping I'm going to see hello world but here we have an error on the screen a so-called syntax error which refers to my having made a mistake at my keyboard and it this one fortunately is pretty straightforward it indeed says that this open parenthesis was never closed and so that's probably pretty intuitive now what I need to do I need of course to close it unfortunately sometimes the error messages we'll see in the coming weeks are not going to be nearly that userfriendly but there too again with experience with practice will you get better at debugging such programs let me now make sure that I indeed fixed it correctly let me go ahead run now hello.py and hit enter and voila we're back in business well let me pause here and see if we have any questions now about python itself writing or running even the simplest of these programs uh could I write code inside a word or for example Microsoft Excel and what's the barrier to doing that a really good question and allow me to very explicitly say to the entire internet that you should not write code with Microsoft Word I mention that only because it's a tool via which you can write text and code is at the end of the day just text but it's not the right tool for the job we don't need bold facing underlining paragraphs and the like we generally want something much simpler than Microsoft Word or Google Docs and so VSS code is an example of just a more general purpose text editor its purpose in life is to allow you the human to edit text nowadays these text editors come with many more features in fact you'll notice that even in my code here even though it's just one line there's a bit of color to it the word print for me is appearing in blue the parentheses are black and we'll see as we might write more lines of code more and more of the lines will come to life in various colors now that's just one feature of a text editor we'll see too that it has features like this built-in terminal window it's going to have a built-in tool for debugging or finding problems with code and it's just a very popular tool nowadays but there are many many others out there you're welcome to use them for this course and Beyond we just happen to use this one in large part too because you can also use vs code nowadays uh for free in the cloud how about one other question here on programming with python or hello world or syntax more generally I was trying to ask if is not possible to run the code without using the terminal window I think I heard is it not if it's possible to run the program without the terminal window are you yes sir okay you froze for me again but let me infer what the question is so in this environment as I've configured my computer I can only run these python programs via the terminal window now that's good for me the programmer or the person who's trying to learn how to program but it's not very good if you want to ship this software and have other people use your actual code you can absolutely write programs and then allow other people to use not a command line interface but a graphical user interface or guey GUI this is just one mechanism and perhaps I think the the best one with which to start writing code because eventually it's going to give us a lot more control allow me to forge ahead here but please feel free to continue asking questions along the way if only via the chat let's consider now how we might go about improving this program let's go about improving this program to make it a little more interactive and not just assume that everyone is going to want to be greeted more generically as hello world let's see if I can't get this program to say something like hello David or hello Jeremiah or hello Horatio or whatever the actual user's name is well to do this I'm going to go back up to hello.py and I'm going to add another line of code at the very top that simply says for instance uh what's your name quote unquote with an extra space at the end so I'm printing to the user asking them a question for some input but now I need another function to actually get input from the user and perfectly enough python comes with a function named input so here I'm going to go ahead and call a function input open pen close pen and that's going to prompt the user with just a blinking cursor waiting for them to type something in now it turns out if I read the documentation for the input function it actually takes an argument itself I don't need to use print separately and then promp the user for input so I can actually simplify this code before we even use it I'm going to go ahead here and take that same string from print put it as an argument to the input function and get rid of the print alt together and in fact that print would have added a new line anyway so now I've just got a prompt where the user's cursor is going to end up blinking at the end of the line asking them what's your name in my terminal window I'm going to run python of hello.py enter okay we're making progress it seems that this new function input is indeed prompting me the human for input so I'm going to type in my name David and hit enter unfortunately it doesn't really do anything with my name it just outputs it immediately all right well I could fix this right I could go up to line two and I could change world to David and then back in my terminal window here I can do python of hello.py enter what's your name David enter and there we go all right now I'm up and running now my program is working as intended of course this isn't really working as intend Ed here let me go ahead and try pretending to be my colleague Carter here well Carter's name is this I'm going to go ahead and hit enter and I'll see of course hello Carter well obviously not because I've hardcoded so to speak I've written literally my name inside of the string so we need some way now of actually getting back what the user's input is and doing something with It ultimately and for this we're going to leverage another feature of programming specifically a feature of some functions which is that they can have return values as well if you think of input as being again this action this verb you can actually personify it as maybe a person like a friend of yours that you've asked a question of and you've asked your friend to go get input from someone else go ask that person their name and if your friend comes back knowing that person's name well wouldn't it be nice if they handed that name back to you that's kind of what we need metaphorically the function to do is get the user's input and then hand it back to me so that I the programmer can do something with it but if it's going to be handed back to me I kind of want to put it somewhere so that I can then print it back on the screen I need to do the equivalent of take out like a piece of paper or a Post-It note write down on this piece of paper what it is the human has said so that I can then feed it into as input that print function and to do that we're going to need one more feature of programming namely variables and odds are most everyone's familiar with variables from math class way back when X and Y and Z and the like well programming has that same capability this ability to create a variable in this case in the computer's memory not just on a piece of paper and that variable can store a value a number some text even an image or video or more a variable is just a container for some variable a variable is just a container for some value inside of a computer or inside of your own program so how do I go about expressing myself in this way well I think what I'm going to do is introduce a variable that's a little more interestingly named than x or y i i could just say this x equals input but I'm going to use a better name than a typical mathematical variable here and I'm going to literally call my variable name why well in programming because I have a whole keyboard in front of me I can use more descriptive terms to describe what it is I'm writing and now though there's an opportunity to consider a specific piece of syntax we've seen parentheses we've seen quotes all of which are necessary when passing inputs to a function but this equal sign here that's in between input on the right and name on the left is actually important and it's technically not an equal sign per se it doesn't mean equality as much as it means assignment so in Python and many programming languages a single equal sign is the assignment operator and what that means specifically is that you want to assign from right to left whatever the user's input is so the equal sign copies from the right to the left whatever the return value of the function on the right is so again the input function clearly gets input from the user that's why I was able to type my name or Carter's but it also sort of behind the scenes hands that value that return value back to me the programmer and if I use an equal sign in a variable no matter what I call it I can store that input in that variable so is to reuse it later so now sitting in the computer's memory somewhere is a container containing David quote unquote or Carter quote unquote or whatever the human has typed in but here it's easy to make a mistake suppose I decide to try to print that name and so I I kind of on a hunch type in this hello comma name just kind of plugging in the name of the variable well let me go ahead here and run python of hello.py and hit enter that's going to prompt me for my name and let me type in my name daid but I haven't hit enter yet and perhaps via the chat what's going to happen here when I now hit enter I'm hoping it says hello David I'd be okay if it says hello world but I don't want it to say what it's actually G to say and yep what we're seeing in the chat is well it's probably going to say literally hello comma name so that's not quite right so we need another way of printing out the value inside of that variable rather than just this word name well let me try this in a couple of different ways let me try this as follows let me go ahead and maybe undo this because I've gotten pretty good already at saying hello so let's let you know let's draw that Line in the Sand and just say all right let's get at least get hello comma out the door let's now print name and just on a hunch I'm going to try this I'm going to use print again because you can use these functions as many times as you need and I'm going to pass to the name to the print function the variable called name but notice I'm being a little clever now I'm not putting it in double quotes because we've seen already that double quotes means literally print out n m I'm getting rid of the quotes this time in hopes that now by passing the variable called name to the function called print it will in fact go about printing printing the contents of that variable that is its so-called value all right let's go ahead and do this here python of hello.py enter what's your name David and now crossing my finger still I see hello comma David all right so it's not the best program I'm I'm kind of cutting some Corners here so to speak I'm saying hello David on two separate lines so it's not as elegant it's not as pretty it's not as grammatically appropriate in English as just saying it all in one breath on one line but at least I've solved the problem just not very well yet but let me take a step back now and perhaps introduce a couple of other concepts with which we should be familiar which is as our programs get longer and they're no longer just one line or two or even three eventually our programs are going to become dozens of lines maybe even hundreds of lines long let's set the stage for Success moving forward it turns out that python and a lot of programming languages also support something called comments comments are notes to yourself in your code and you include comments by way of a special symbol in Python it's going to be the hash symbol typically and that allows you to write the equivalent of a note to yourself but in a way that's not going to break your code the computer actually ignores your comments it's just there for you it's just there for your teacher it's just there for your colleague with whom you're sharing ultimately that code so if I go back to VSS code here and I just want to add some comments to this program to explain to my teacher to myself to my colleagues what this program is doing well let's go ahead and do that I'm going to go at the very top of my program and on line one now I'm going to move that original line of code down a bit I'm going to add a hash and I'm going to say something like this uh ask user for their name now I don't have to use that language I don't have to use that uh that text I could use any human language whatsoever it doesn't have to be English but I'm going to now below that just say something like this say hello to user and you'll notice that vs code by default is kind of graying out my comments they're no longer blue there's no red there's no color in them and that's just because they're notes to myself and the computer ultimately is going to ignore them but what we have now is two comments ask user for their name and then a second comment say hello to user and I've just kind of commented each chunk of code like each line or lines plural of code that are doing something noteworthy why well tomorrow morning when I wake up having you know uh uh slept for quite some time forgotten what it is I did the previous day it's convenient with comments to just see in English or your own human language what it is this program is doing so that you don't have to read the code itself and better yet if there's maybe a mistake down the road you can read what your intention was and then you can look at the code and figure out if your codee's now doing what you intended so this isn't really necessary for a program this small it's pretty obvious with just one or two or three lines what the program is doing it's just as fast to read the code than the comments but getting into this habit is generally a good thing to comment your code every one or few lines so is to remind yourself and others what it is your intent and your code is doing what's nice about comments too is this comments can also serve to be sort of a to-do list for yourself there's this notion in uh programming of pseudo code pseudo code isn't a formal thing it's not one specific language it's just using English or your own human language to express your thoughts succinctly methodically algorithmically so to speak but pseudo code therefore because it's not Python and it's not necessarily English it just kind of allows you to outline your program even in advance so for instance if I wasn't sure today how I wanted to go about writing this program but I did know what I want to do I could have started today by just writing this in hello.py no code I could have written just a couple of comments to myself step one ask user for their name step two say hello to user then once I've outlined my program in pseudo code then I can go in there and say all right how do I ask the user for their name uh well I can do input quote unquote what what's your name question mark and then on the left here I can maybe put a variable and assign it to that okay how do I say hello to the user well I know I can use print to say things on the screen let me say hello comma uh and let me okay let me now print the person's name so again pseudo code is a nice way of structuring your to-do list especially if you have no idea how to write the code because it breaks a bigger program down into small bite-size tasks all right let me pause here to see if there are now any questions on comments pseudo code return values or variables any questions we can clear up here yeah my question is uh does the function input uh work for any type of of information or only for Words yeah really good question so according to its documentation and we'll look more at formal documentation soon input is going to expect what's called a string that is a sequence of text be it in English or any other human language but it's indeed going to be expecting text with which to prompt the user a good question how about another question from the group if we could I wanted to ask how I make several line comment oh how do you do many lines of comments if if I'm hearing you correctly sure uh you would just keep doing them like this you just prefix each of the lines with a hash symbol like I'm doing here there is another technique for doing multi-line comments in Python that actually tend to have special meaning you can do three double quotes like this and then anything in between here is a comment that's another technique or you can use single quotes as well but more on those I think another time all right well if you don't mind let me Forge ahead here and see how we might improve this program further and also introduce a few other features that we might want to take into account over time so it turns out that we can certainly improve on this program because it's a little disappointing that I'm cutting this corner and saying hello comma and then on a new line print out name like we can do better and most programs you use on your phone or your laptop certainly keep text together when people want so how can we go about doing that well there's a few different ways and in fact the goal here is not so much to solve this one problem but to demonstrate and emphasize that in programming Python and other languages there's so many ways sometimes to solve the same problem and here's one way to solve this problem let me go in here and let me go ahead now and say hello comma and let me just add to the end of that the user's name so I'm using Plus in kind of an interesting way this is not addition per se I'm not adding numbers obviously but I do kind of want to add the person's name to the string of text hello comma well let me go now down to my terminal window and run python of hello.py again enter what's your name I'm going to type in David enter okay it's better it's better but there's a minor bug albeit aesthetic here there's missing space but let's just use some intuition here well if I'm missing the space after the comma why don't I go ahead and just add it manually here let me now rerun the program python of hello.py enter David enter and there we go now we have something that looks a little prettier in terms of English grammar hello comma space David and now if we rewind you might have noticed before or wondered why I had this seemingly extra space after my question mark namely here there's a space after the question mark but before the double quote and that was just for Aesthetics to I wanted to move the user's cursor one space to the right so that when I type their name or they type their name it's not immediately next to that same question mark there but there's other ways we can do this it turns out that some functions print among them actually take multiple arguments and it turns out that if you separate the inputs to a function the so-called arguments to a function with a comma you can pass in not just one but two 3 four five onward so let me go ahead and pass in not just hello comma space but that followed by name and this is a little confusing potentially at first glance because now I've got two commas but it's important to note that the first comma is inside of my quotation marks which is uh simply an English grammatical thing the second comma here is outside of the quotes but between what are now two separate arguments to print the first argument is hello comma space the second argument is the name variable itself so let's see how this looks python of hello.py enter what's your name David enter okay I've kind of overcorrected now I've got two spaces for some reason well it turns out and this is subtle when you pass multiple arguments to print it automatically inserts a space for you this was not relevant earlier because I was passing in one big argument to print all at once by using that plus operator this time I'm passing in two because of the comma so if I don't want that extra space I don't need to pass in one myself I can just do this and now notice if I run this program again python of hello.py type in my name David now it looks grammatically like I might want now which of these approaches is better this approach uses a function print with two arguments hello comma and the name variable the previous version recall technically used one argument even though it looked a little curious It's one argument in the sense that the computer just like mathematicians are going to what's inside of parentheses first so if inside of parentheses you have this string of text hello comma and a space which I need to add back then you have a plus which means not addition per se but concatenation to join the thing on the left and the thing on the right this ultimately becomes the English phrase hello comma space David and then what's being passed ultimately to the function is technically something like this but it's doing it all dynamically it's not me typing in David as I I secretly as I discreetly did earlier it's figuring out dynamically what that value is after concatenating hello with the value of name and then passing that ultimately to print as the sole argument let me pause here to see if there's any questions on numbers of arguments now to functions can we use a function uh many times to solve a certain problem which we can encounter many times in our code you can you can can use a function many different times to solve some problem what we'll soon see though is if you find yourself as the programmer solving a problem the same way again and again and again it turns out you'll be able to make your own function so that you don't have to keep reusing the basic ones that come with the language I was curious about the comma and the plus sign so after plus sign can we give just one variable and after Comm again we give multiple variables like what is the difference a good question so in the context of strings and I keep using that term string is a technical term in a programming language and again it means a a sequence of text a character a word a whole paragraph even so the plus operator is not just used as we'll see for addition of numbers in Python like we do on paper pencil but it also is used for concatenation of strings on the left and the right if you did want to combine not just two strings left and right but a third and a fourth you can absolutely keep using plus plus plus plus and chain them together just like in math eventually that's going to start to look a little ugly I dare say especially if your line of code gets long so there's better ways that we'll actually soon see and a good question as well well let me come back to the code here in question and see if we can show you just a couple of other ways to solve the same problem along the way emphasizing that what we're technically talking about here yes are strings but there's even a technical term for these strings in Python it's just stir so to speak St for short for string as you may know if you programmed in other languages people who invent programming languages like to be very uh succinct to the point so we tend to use fairly short phrases to describe things not necessarily full words so while you might say string technically in Python what we're really talking about these sequences of text are technically stirs this is an actual type of data in a program but we'll soon see that there's other types of data in programs as well in fact let's see if we can't improve this in one other way I like the progress we've made by keeping everything on the same line hello comma David all on the same line what more though could we do in terms of solving this problem well it turns out that we didn't have to give up entirely with using print twice let me rewind a little bit and go back to that earlier version where I wasn't really sure how to solve this problem so I was using print once to print out just the hello and the space and the comma and then I used print again to call uh to print name that strictly speaking wasn't bad but there was this visual side effect that I just didn't like it just looked ugly to have these two lines of text separate from one another but there's another way to fix this clearly it seems to be the case that the print function is automatically outputting a blank line it's moving the cursor automatically for me to the next line because that's why I'm seeing hello on one line and David on the next and then my prompt the dollar sign on the line below that so print seems to be presuming automatically that you want it to move the cursor to the next line after you pass it some argument but you can override that behavior again functions take arguments which influence their behavior you just have to know what those arguments are and it turns out that if we look at the documentation for Python's print function we can actually look up at this URL here docs. python.org is where all of Python's official documentation lies if I poke around I can find my way to more specifically this URL here where I can find all of the available functions in Python that and the documentation therefore and if I go a little more precisely I can even find specific documentation for the print function itself and rather than pull that up in a browser I'm going to go ahead and highlight just one line from that same URL which is this and this is easily the most cryptic thing we've seen yet but this is the official documentation for the print function and one of the best things you can do when learning a programming language is honestly learn to read the documentation because truly all of the answers to your questions will in some way be there even though admittedly it's not always obvious and I will say too Python's documentation isn't necessarily the easiest thing especially for a first time or novice programmer it too just takes practice so try not to get overwhelmed if you're not sure what you're looking at but let me walk you through this example this again is a line of text from Python's official documentation for the print function what this indicates as follows is this the name of this function is of course print then there's a parenthesis over here and another Clos parenthesis way over there everything inside of those parentheses are the arguments the potential arguments to the function however when we're looking at these arguments in the documentation like this there's technically a different term that we would use these are technically the parameters to the function so when you're talking about what you can pass to a function and what those inputs are called those are parameters when you actually use the function and pass in values in inside of those parentheses those inputs those values are arguments so we're talking about the exact same thing parameters and arguments are effectively the same thing but they terms you use from looking at the problem from different directions when we're looking at what the function can take versus what you're actually passing into the function so what does this imply well this syntax is pretty cryptic but at the moment just know that an asterisk a star and then the word objects means that the print function can take any number of objects you can pass in zero strings text one string like I did two strings like I did or technically infinitely many if you you really want though that code's not going to look very good after that we see a comma then we see another parameter here called sep short for separator in English and notice the equal sign and the single quote space single quote so quote unquote space I don't know what that is yet but I I I think we've seen a hint about it let's focus though for a moment on this the print function takes another parameter called n and the default value of that parameter is apparently based on this equal sign and these quotes back sln and what is backs slash n if you'd like to chime in the chat anyone who's programmed before has probably seen this though if you've never programmed before this might look quite cryptic back sln means new line and it's a way textually of indicating if and one you want the computer effectively to move the cursor to the next line create a new line of text and so technically if we read into the documentation we'll see more detail on this the fact that there's a parameter called end in the documentation for the print function just means that by default this print function is going to end every line with back slash n you don't literally see backs slash n you see a new line you see the cursor moving to the next line now by that logic let's move backwards sep for separator the default value of separator is apparently a single Blank Space well where have we seen that well recall in an earlier example when I passed in not just one but two arguments to the print function recall that they magically had a space between them in fact they had that space plus my own space and that's why I deleted my space because at that point it was extra so this just means that when you pass multiple arguments to print by default they're going to be separated by a single Space by default when you pass arguments to print it's the whole thing is going to be ended with a new line now just by knowing this and let me let me literally wave my hand at the rest of the documentation for another day there's more things that print can do but we're going to focus just on sep and on end let's see if we can't leverage this now to solve that original problem the original problem was this I don't like how hello comma David is on two different lines well that's happening again because print is automatically printing out a new line so let's tell it not to do that let's Tell It by passing a second argument to the first use of print to say end equals quote unquote not back sln which is the default automatically let's make it quote unquote nothing else let's override the default value so there is no new line there's literally nothing there and let's see what happens let me now go down to my terminal window and clear it and I'm going to run python of hello.py enter I'm going to type in my name David and I think now everything's going to stay on the same line because and it did this line here five is going to print out hello comma space but then nothing at the end of it because I changed it to be quote unquote the second line is going to print the name David or whatever the human's name is and it will move the cursor to the next line because I didn't override the value of end there just to see this more explicitly if you do something cryptic like well I have no idea what's going on let me just put in temporarily three question marks here we'll see the results of this too let me go back down to my terminal window run python of. hi what's your name David and now you see literally really ugly output but you see literally what's going on hello comma space then three question marks and that print statement and then you see d a ID so not a good out outcome but it demonstrates just how much control we have here too and let me rewind further recall that in our other version of this when I passed in hello comma and name they were separated by a single space so Pyon of hello.py D Aid enter that just worked well what if we override the value of sep for separator instead of being one space we could say something like uh question mark question mark question mark just to wrap our minds around what's going on there let me now do python of hello.py David enter and you see two these two inputs hello comma and the name are now separated in an ugly Way by three question marks Mar s because I've overridden the default behavior of sep and even though the documentation uses single quotes I've been in the habit of using double quotes in Python you can use either strictly speaking it doesn't matter but you should be consistent and I generally always use double quotes Python's documentation though always uses single quotes questions now on these types of parameters and allow me to propose that we give these an official name up until now when we've been passing values to print those are called positional parameters positional in the sense that the first thing you pass to print gets printed first the second thing you pass to print after a comma gets printed second and so forth but there's also these things we've now seen called named parameters named sep separator or end end D for the line ending those are named parameters because one they're optional and you can pass them in at the end of your print statement but you can also call uh use them by name this may be aird question but I was wondering uh what if someone wants to like add actually qu quotation marks within the quotation marks yeah I like how you think this is what we would call a corner case right just when we've made right this is this is all sounding great at least as as programming goes but wait a minute what if you want to print a quote that's a really good question well let's see if we can't figure this out suppose that I want to print out not just the user's name let me simplify this further let me go ahead and get rid of a lot of this and let me just say something like hello um maybe I'm being a little sarcastic here hello friend you know in that kind of tone well this is not going to work actually because you are trying to use quotes to be like friend in finger quotes but you're also trying to end the sentence and if I try running this let's do this python if hello.py you'll see that this is just invalid syntax perhaps you forgot a comma and this is actually a bit annoying sometimes the error messages you see are misleading like the computer the language doesn't really know what's going on so it gives its best guess but it's not necessarily correct but I can solve this problem in a couple of ways I can do this I can change my outermost quotes to single quotes because recall a moment get I said you could use double quotes or single quotes so long as you're consistent so that's fine if you use single quotes on the outside you can then use double quotes on the inside and you'll see them literally so for instance if I run python of hello.py there we go hello friend but there's another way if you insist on using double quotes as you might want to just to be consistent you can also use that backslash character again we saw the backs slash n a moment ago and that meant we don't want a literal n to be in the output we wanted a new line so the backslash actually represents what's called an escape character an escape character is one that you can't just type necessarily once on your keyboard you need to express it with multiple characters so I can actually put backslashes in front of these inner double quotes so that the computer realizes oh wait a minute those aren't literal those aren't quotes that finish or start the thought they're literal quotes So now let me go back to my terminal window run python of hello.py enter and now it's working as well so escaping is a general technique that allows us to do that too and if I may let me rewind now on these examples and go back to where we left off with my code I'm just undoing all of that because I want to get back to the point ultimately of specifying now a a final way of solving this problem well it turns out that we have yet another way we can solve this problem which is perhaps the most frequently done now or at least the most elegant when it comes to setting us up for longer and longer uh uses of strings you can use a relatively new feature of python that allows you to do this you can literally put not the name of the variable like that in your string because we already saw this is right if you do this you will literally see hello comma name but what if I do this what if I put curly braces or curly brackets around the variable's name notice vs code is actually very subtly changing the color of it so vs code knows something interesting is going on here let me run this program but I'm not done yet python of hello.py enter David enter okay obviously not what I want but I need to tell python that this is a special string this is what we're going to call a format string or an F string a relatively new feature of python in the past few years that tells python to actually format stuff in the string in a special way and the symbol via what you do this is a little weird but this is what the world chose if you put a f at the beginning of the string right before the first quote Mark that's a clue to python that o this is a special string let me format this in a special way for you let me now rerun the program python hello.py enter David enter and now we see the goal this whole time hello comma David we don't start with this way because I think if we did this the first way you'd be like why are we doing this what are all these magical symbols but this is just yet another way to solve the same problem but let me propose that we consider now yet other things we can do with strings and it turns out that even as we've been doing some relatively simple operations here we've generally been trusting that the user is going to cooperate and that is to say that they're going to actually type in what we want them to type now now just because they type A String though doesn't mean it's going to look the way we want you and I honestly as humans are actually in the habit on websites and apps of like accidentally hitting the space bar a lot either at the beginning of our input or at the end maybe because the space bar tends to be so big it's pretty common to get accidental spaces before or after some users input you and I are definitely in the habit of not necessarily capitalizing words like we should if we're sending text messages we're probably being a little quick and just sending everything in lowercase for instance if that's your style if your phone's not fixing it for you maybe in a formal letter you would capitalize things properly but you and I as humans we can't really be trusted to type things in a nice way necessarily when using some piece of software be it an app or website or something else but it turns out that strings themselves come with a lot of built-in functionality and you can see all of that in Python's own documentation here the string data type that we've been talking about comes with a lot of functionality built in that means that we can manipulate the user's input to do more than just join it with something else like hello we can actually clean it up or reformat it in a way that hopefully looks a little better for us so let me go back to my code here and let me just demonstrate what might happen if a user doesn't cooperate if I go ahead here and run python of hello.py enter let me just sloppily hit the space bar a few too many times why I just wasn't paying attention and I'm going to type in my name da viid and I don't know I hit the space bar a couple more times like it's kind of a mess it's all lowercase that's not going to necessarily look grammatically right it's got spaces here and here the program is going to print exactly that and that looks really bad at least if we're prioritizing Aesthetics and grammar like why are there so many spaces after the comma this is not a very nice way to greet your users but we can clean this up it turns out that built into Strings which again is this data type so to speak this type of data in Python is the ability to actually do things to that string so let me do this I can actually go ahead and do something something like this uh name equals name. strip and what does this do remove Whit space from string and what do I mean by this well on the right hand side notice I've written the variable name called name I've then used a period or a DOT and then I seem to be doing what's a function right anytime we've seen a function thus far we see it's the the function's name print or input then we see a parenthesis then another parenthesis and that's exactly what I see here but I'm using this function a little differently technically this function is in this context called a method and what do I mean by that well if name is a string AKA stir well it turns out according to the documentation there's a lot of functions that come with strings in Python and you can access that functionality by using the name of a string like literally name here then a period Then the name of the function and then an open parenthesis and a closed parenthesis Maybe some arguments inside of those parentheses but in this case it doesn't need any arguments I just want to strip the space from the left and the space from the right of the user's input but that's not enough I want to remember that I've stripped off that white space on the left and the right so I'm going to use the equal sign again here and notice that just as before this doesn't mean equality this means assignment from right to left so when this line of code here name. strip returns to me AKA a return value it will return the same thing that the user typed in but with no more white space to the left or to the white to to the right so then the equal sign assignment is going to copy that value from the right to the left thereby updating the value inside of my name variable so you can not only assign values to variables you can absolutely change the value of variables by just using the assignment operator the equal sign again and again and again and it will just keep copying from right to left whatever the new value should be so now now if I rerun this program python of hello.py enter I have Davi oh let's do it again space space space space space daav ID in all lowercase space space enter it's better it hasn't fixed my capitalization so I'm still being a little sloppy with the first D but it has stripped off all of that extra space super Minor Detail right like this isn't all that exciting but it just speaks to the power of what you can do with just a single line of code now what else can I do here well I could capitalize the user's input let me go ahead and try this it turns out that I could also uh do this name. capitalize so let me go ahead and capitalize uh user's name and again I'm making comments and there's no one right way to write the comments I'm just using some short English phrases here to remind myself of what I'm doing what's now going on here well let me go ahead and run python of hello.py enter uh space space space space space DAV ID space space enter okay now it's looking prettier right no matter how the user typed in their name even a little sloppily I'm now fixing that but let's let's try something I'm getting a little curious here how about this uh space space space space space David space maen I'll use my last name now enter okay so ironically capitalize is not really capitalizing everything we want it's clearly capitalizing what just the very first letter so it turns out that again there's other functions in in Python that come with strings and if we poke around the documentation scrolling through a URL like that I bet we'll find another solution one of which is actually this let's actually change this to title there's yet another function that come with strings called title that do title based capitalization just like a book or a person's name capitalizing the first letter of each word and this is just going to do a little more work for us so let's go ahead and run this and as an aside I'm kind of tired now at this point of typing python python python all the time it turns out that when using a command line interface like this you can actually go back through all of your old commands what I just did a moment ago was I hit the up arrow that immediately goes back through my history of all of the commands I've ever typed so this is just a faster way now for repeat myself than typing everything manually let me go ahead and hit enter uh space space space space space DAV ID mailin space space all lowercase enter now it's it's looking better now I've capitalized things and cleaned things up but what about my code I've got like eight lines of code now four of which are comments four of which are actual code do I really need this much well not necessarily watch what I can also do in Python let me not bother capitalizing the user's name separately let me say this and capital uh capitalize users name I can chain these functions together I can add title to the end of this and now what's happening well again with a line of code like this you first focus on what's to the right of the equal sign then we'll get to the left of the equal sign what's on the right of the equal sign this line here well what does this mean get the value of the name variable like daavid space m n then strip off the white space on the left and the right that is going to return a value it's going to return da ID space m n without any white space to the left or right what do you want to do with that return value you want python to title case it that is go through every word in that resulting string and fix the first letter of the first word the first letter of the second word and so forth and then now we can finish our thought copy the whole thing from right to left into that same name variable and you know what I can take this even one step further why don't we go ahead and do this if we want let me get rid of all that and let me just do strip and title all on that first line and now we've gone from like eight lines of code to four it's a lot tighter it's a lot neater and even though reasonable people might disagree it's arguably better because it's just easier to read fewer lines of code fewer opportunities for mistakes it just allows me to move on with my next problem to solve all right let me pause here and see if there's any questions on these methods a method is a function that's built in to a a type of value like these functions are or on F strings which we saw a moment ago yes hi thanks David um so is there a way to remove the spaces between the spaces that I might have added a short answer no if you read the documentation at that same URL earlier you'll see that strip removes from the left and the right but not in between in fact there's two other functions that come with strings one's called L strip the other's called R strip that allow you to do one or the other if we want to start getting rid of space in the middle we're going to have to do a different trick Al together how many functions can we combined like this do stripe do title you have combined so how many we can combine yeah a really good question technically as many as you want but at some point your codee's going to start to look really really bad right because the line of code's going to get really really long it's eventually going to maybe wrap around again and again so at some point you just kind of say like uhuh that's too many and you start breaking it up into multiple lines like I did maybe reassigning the value to the variable as needed and this is actually a good question if I can pivot div off your question I mean what do people think if we could go ahead and put everyone's hands down for a moment let me ask this is the way I've done this now with strip and title and input all in the same line better than my previous approach in Zoom you can use the yes icon or the no icon if you think this version is better say yes if you think this previous version was better for instance this one here where we had everything broken out say no and then we'll see why in just a moment I proposed earlier that reasonable people can disagree and that's absolutely the case doing it one way or the other isn't necessarily best at least if you can justify it let me go back to the most recent version here all right so we're seeing a lot of yeses and a lot of NOS why don't we go ahead and and call on one of the yeses if if we could someone who's voting yes why do you think the current version of this code is indeed better than the previous longer version of the code I think it's more readable so I can say hey this is the name fun this is the name variable it gets some input and then remove the space and give it a title and there you go you have a Hello name yeah I think that's pretty reasonable it's very readable at least if you're in the habit as you are in English of reading left to right it just kind of flows very naturally as a result the lines is not really that long it's certainly fitting nicely onto the screen so I think that's a good argument how about a Counterpoint though someone who voted no if we could call on someone who thinks this is worse uh because it's not avilable at all uh it seems like uh it's a very long uh line so I think it's better to separate yeah I I think that's persuasive too right it's getting a little longer and even though my sentence here what's your name is relatively short you could imagine that this could get even uglier quickly if I were asking a longer question of the user that's going to make this line of code even longer and therefore less readable it might be less obvious to me or my colleagues that I am calling strip or that I am calling title it might be kind of a unexpected surprise so I think that's reasonable too in short there is no right answer here and in fact part of the process of getting better at programming is getting your own sense of style or working for a company where they might prescribe which way is better than the other because they just want everyone doing the same thing even though reasonable people might uh disagree ultimately though so long as you have what's a pretty good argument in favor of one way or the other like ultimately that's what's important if you're just doing things because you don't really know which one's better that's not great but if if and when you start to acquire opinions and if your boss if your teacher if your colleague your friend can challenge you and say wait why did you do it like this they might not agree with you but at least have an answer and that should be sufficiently persuasive in general now strings come with a whole bunch of other methods as well among which is one called split which can as the name suggests split a string into multiple smaller substring so to speak for instance if the human here is in the habit of typing in their first name then a space and then their last name and you want to go ahead and greet them only by first name well we could actually leverage that single space between the first name and last name and split that string into two smaller substrings how can we do this well let me go ahead and in between these lines proactively comment that we're about to split user's name into first name and last name and then let's go ahead and take that name variable which currently contains something like presumably David space Ma and let me go ahead and call split and pass in as the argument to split a single white space thereby indicating that I indeed want to split on that character now it turns out split's going to return a sequence of values ideally a first name and then a last name and we can actually in Python assign both of those values from that sequence at once to some variable for instance first comma last equals and that's going to have the effect from right to left of putting the first such value in the first variable the second such value in the second variable so now on my last line of code I can go in and say hello not to the full name something like David man I can just say hello comma first all right let's go ahead and clear my terminal window run python of hello.py and hit enter I won't bother with any leading Whit space this time but let me go ahead and type in David space maen and crossing my fingers is as usual hello David is what we now see all right so we've seen so much so many examples thus far involving strings but certainly programs uh and programming languages can manipulate other types of data as well let's go ahead and transition then to another very common type of data in Python in programming more generally namely integers otherwise known in python as int int so just as stir St Str is short for string so is INT in Python short for integer well what's in an integer well just like in math it's a number like -2 Nega 1 0 1 2 and all the way toward negative Infinity all the way toward positive Infinity but there's no decimal point in an integer it's just a number like -2 Nega 1 0 1 and two onward that's an INT of course in the world of mathematics there's lots of symbols that we use and we've seen plus before although we used it for different purpose but python supports these symbols and more and python allows you to add numbers together plus subtract numbers uh multiply numbers divide numbers and the only one here that might look a little strange to people or unfamiliar is this percent sign but it doesn't mean percent in this context if you use a single percent sign in a Python program that's actually the so-called modulo operator the operator that allows you to take the remainder after dividing one number by another so we'll see examples of that before long but the first four of these are perhaps quite quite familiar well it turns out that in Python you cannot necessarily you don't necessarily have to keep writing code in a file like hello.py and then running it in a terminal window one of the features that many people like about python is that it supports this a so-called interactive mode like you can start writing python code and immediately execute each of those lines interactively if especially if you don't care about saving all of your lines of code you just want to execute code and get back some answers so for instance let me go back to VSS code here and let me close hello pi and let me click on the Little Triangle over here in my terminal window just to make it much bigger just temporarily for a moment so I'm not creating any piy file now I'm just going to run python by itself at my prompt and you'll see when I do this I get some cryptic looking output and the date and time at which the program was last updated and so forth but I ultimately get three triple uh brackets like this this is the interactive mode for python so I'm running the python interpreter and anytime I type A Comm a line of code in The Interpreter it's going to execute it immediately I don't have to keep running python again and again it's as though in the human world if you were standing next to a human who speaks some other language and you're just having a conversation with them back and forth It's all happening the translation immediately so what might I do in interactive mode well I could do something like 1 + one enter that's actually code right you might not think of it as code but if you know a bit of arithmetic and you know uh numbers and you know plus that's valid python code and you can use Python really as a fancy calculator but I could do other things too if I want to print to myself hello comma world I can also print out that line of code there too hello world so it's interactive in the sense that the moment you execute a line of code boom you see the result we're generally not going to do that because at least when teaching the language we tend to want to do things incrementally and we want you to be able to see where it is we came from and we want to be able to try things again in again especially if we make mistakes but know that this is indeed a feature of python this so-called interactive mode but let's focus for a moment now not just on that interactivity but really on the fact that python apparently supports integers and Mathematics and some of those basic operations and let's see if we can't make maybe our our own little calculator so let me go ahead and open up vs code again and I'm going to shrink down my terminal window and I'm going to create a new file called calculator. piy so to do that recall I can type code down here here and the name of the file I want to create Pi enter that gives me a new tab up top so I have already closed hello.py I'm now in calculator. piy and let's just make a simple calculator that does some addition for me but I'm going to do it in a file so that we can iterate on this and make changes For Better or For Worse over time let me go ahead and first declare a couple variables I'm going to do the mathematical thing of calling my first variable X my second variable Y and then I'm going to give myself a third variable Z equals x + y and then I'm going to go ahead and print out Z now this program admittedly not very exciting or interesting in fact it's a little less interesting than printing stuff on the screen like before with strings but we'll build on this and see what other features exist in Python that we can leverage so hopefully if python knows its math as well as I do when I run python of calculator. piy I should see hopefully that 1 + 2 equals indeed three all right so not that surprising and not that that interesting and honestly this isn't the most useful program because it's always going to calculate 1 + 2 equal 3 let's at least make this program say a little more interactive right we already know from previous examples how we can get input from the user let's bring back that input function and let's do this let me go ahead now and at the top of my code let's change X to not be the number one always let's change it to be whatever the return value is of asking the user for x and I can use any English or human language I want here I'm going to say what's X just like I asked before what's your name and I'm going to do the same thing for y I'm going to use input again but this time change the question to be what's why all right at this point I think I'm going to leave the rest of the code the same Z equals X Plus Y and then print Z but what's nice now is that I think I have a nice interactive calculator right now it's not going to do 1 plus two all the time it's going to do whatever the user types plus whatever the user types so let's try this let me go ahead and run the program all right let's do it one is going to be x two is going to be Y and of course everyone in agreement 1 + 2 equals 3 huh what's going on there either your math class misled you or I have misled you why don't we call on someone here to see if you can't help us reason through what the bug is what's the mistake uh on jalli if I'm saying it right I think the issue is is that it's concatenating strings because you use the plus operator instead of adding perfect so perfect intuition we've seen that plus is used a little differently in the context of strings because it concatenates that is it joins the two strings and that seems to indeed be what's happening here even though the user types a number but the interesting thing here is that when you get user input because they're using a keyboard on their Mac or PC or their phone it is always going to be text it might look like a number but by default it's coming from the keyboard as a string that is as text and so how do we go about re uh resolving this if ultimately we don't want to treat those inputs as strings we want to treat them as actual numbers well we need another function and it turns out in Python that you can convert sometimes from one type of data to another type of data for instance from string to int by doing something like this let me go back into my code and let me change X before adding it to Y to be whatever the integer version of X is plus whatever the integer version of Y is so it turns out that int is not only a type of data in Python it's also a function and it's a function that if you pass in an input like a string so long as that string looks like a number like one or like two it will convert it to an actual number that you can perform mathematics on instead so if I now go back to my terminal window and run Python and let me show you another trick calculator is kind of a long word it's a little tedious to type notice what I can do in my terminal window in a command line interface in general if I start typing C for calculator I can actually hit tab to finish my thought so autocomplete is possible in a terminal window like this type the first letter or few letters and then boom with tab it'll finish your thought for you or you can go back in your history like I did with the up and down arrows let me go ahead and execute this what's X X1 what's X2 and there we go now we have a general purpose calculator that's going to support not just uh addition of one and two but now any two integers that the user types and let me now improve this right we've seen how we can make improvements to code and I don't know if it's going to necessarily be better but let's try this do I really need the Z variable it's worth noting that I'm creating a variable called c z and then I'm immediately using it on the next line of code now that's not that compelling because if you're creating a variable and then immediately using it but never again using it did you really need to take the time to introduce another symbol and another variable just to use it once and only once well maybe not maybe we don't really need Z in this way maybe I should go and do something uh like this maybe I should get rid of Z here maybe I should change this to be int up here change this to be int up here here doing something that's pretty interesting now even though it's a bit of new syntax notice that you can Nest function so to speak you can put one function call that is the use of a function inside of the use of another function so that the return value of the inner function becomes the argument to or the input to the outer function so just like in math if you have parentheses parentheses parentheses your teacher probably taught you to focus on what's inside the innermost parenthesis first and then work your way out same thing with programming that's what Python's going to do it's going to look at what's inside of the parenthesis first it's going to get the answer and then it's going to pass the return value to the outermost function so what happens on line one now is that the input function gets called first then the result of that quote unquote one becomes the input to the int function and same on line two the output of what's y becomes the input to this int function and now there is no Z I could just do print x + y and because I've taken the time to convert each of those strings to an integer I think we're okay so let me try this python of calculator. piy enter one and two and we're still getting three not 12 or not 12 one two we're indeed getting three and we've additionally gotten rid of the variable because we didn't necessarily need it it seems especially if only using it once well here too let me put everyone's hands down for just a moment and let me ask as before this version now which uses int around the invocations of input and does not use Z is this better than the previous version if you want to vote yes go ahead or if you prefer the old Way vote no the old way I'll undo all of this as we vote instead looked like this all right and let me go back to now the newest version let's take a hand of the is someone who thinks this latest version is better I think this way is better because it uh allows us to immediately see what the X and Y variables are with um integers and so we know what to expect from them and also the print argument is more U intuitive we avoid too much clutter uh in the codes I think those are all good reasons it's nice and succinct the lines of code are not very long uh I don't need to know what Z is because it doesn't exist it just see print X Plus y I like that but someone who prefers the older way where we did have Z and we more explicitly passed individual variables to the int function yeah hi uh I think the earlier version is better because when uh I mean if user inputs something else other than in let's say I mean let's say the type one and two like so it be it will be easier to debug this version or the this version here or the old version the old version okay that's fair and in fact I'm I'm being very careful today as best I can not to mess up I have thus far only inputed integers when I'm expecting integers and R is actually pointing to something we'll come back to in the coming weeks how do we actually handle errors what if the user doesn't type in the number one or the number two or a number at all what if they type in a word like cat c a t that's not a number and I bet I can't convert it to an integer but for today I'm not going to focus on that I'm just going to hope that the user cooperates but that's not going to be the case and so perhaps one way would set us up for more success when it comes to handling those errors now for today's purposes which is better h i mean I like both and I think both of you made very valid arguments in there too so long as you have a justification that feels pretty reasonable I mean that's what ultimately matters but acquiring again a sense of the tradeoffs here well is this way better if so why or why not just understanding what those trade-offs are but generally speaking prioritizing readability is a very good thing making your code readable for someone else is a very good thing and very good for you too so that when you wake up the next morning or you come back the next week or the next year you too can read your own code without having to waste time trying to remember what you did and simplicity tends to be a good thing too keeping your code simple so is as you get more comfortable with programming you might be tempted to try to like combine an entire program into one long line for instance let me do right just that that don't technically speaking we don't really need X in a variable we don't really need Y in a variable we could also do this I could just get rid of X and Y Al together I could then now eliminate that and make it just one line of code okay so on some sense you might be inclined to think wow that's really nice you made it one simple line of code I would argue this actually isn't that simple now I think I'm starting to Nest too many things I have to think about print and int and input I then have to notice that okay I've opened two parentheses I've closed two of them there's a plus you're making me think too much and anytime you make me think you're wasting time and anytime you complicate the look of the code like this you're just going to increase the probability of mistakes syntactical mistakes or logical errors in your code so of all the things we've done this is the only one that I would argue yes it's one line and it's nice and compact it's just not readable enough I would shy away from doing this especially since two of those function calls are getting input from the user but there too reasonable people might disagree but that's the kind of like visceral reaction you should have sometimes when code starts getting a little too complicated a little too clever perhaps for its own good all right well it's not just integers we have access to let me propose that we transition from integers to one more data type here namely a float so again a string is a sequence of text an INT is an integer like negative 1 0 and one a a float is a number with a decimal point properly called a floating point value and you can think of the floating Point as being the decimal that might be over here or over here with some number of digits to the left or the right mathematically it's a real number a number that has a decimal point in it so that's a third type of data that python supports right now our calculator is somewhat naively assuming that the user is only going to type in integers but if I want to support floating Point values too I think I can just make a couple of tweaks so I'm going to go back to VSS code here and instead of just converting the user's input X and Y to integers on line one and two let's just make a simple change let's actually convert it to a float on the first line and a float on the second line here now I think if I go down to my terminal window and run python of calculator. Pi let's type in a number like 1.2 with a decimal point and 3.4 with the decimal point and there we go we have 4.6 as the final answer so that wouldn't have worked before if I were only expecting integers from the user but now that I'm support expecting floating Point values and accommodating it I can actually now do floating Point arithmetic as well but suppose that I don't really want the final answer to be a floating point value like 4.6 I would be happy if we just round to the nearest integer so I want to support the user typing in floating Point values with decimal points but at the end of the day I just want to round the result to the nearest possible integer for instance well it turns out out that here too python comes with some functionality built in and in fact if we return to this URL from earlier where in all of the Python built-in functions are listed there's one called round which does exactly as we would expect it takes as input a number and then rounds it for us for instance to the nearest digit to the nearest integer but if we look a little closer at that documentation as we can here I'll provide an excerpt this is what the function looks like in the documentation and recall that earlier we looked at the documentation for print and this is similar in spirit that this shows us not just the name of the function but it's available parameters that is inputs that we can provide when using this function but this is a little cryptic too just like Prince was and it adds some syntax so let's see the name of this function here is of course round and its first argument is a number notice this times there's no star there's no star objects like there was for print the round function takes just one number as its first argument period that's it positional parameter but notice this syntax and this is a convention in programming or technology more generally generally speaking when you see square brackets in documentation like this this means that you're about to see something optional and so what this means is that if you want to specify more precisely the number of digits that you want the round function to round to you can specify it here by adding a comma and then that number so if we read the documentation if you don't specify a number of digits you just specify the number to Round it rounds to the nearest integer but suppose you want to round to the 10's place or the hundreds place that is one or two digits after the decimal point you could additionally pass in comma one or comma 2 to be more precise so that's what the documentation there is saying let's see if we can't then translate this to some actual code for us so if I go back now to vs code and I consider that I want to go ahead and round X and Y I can do this in a couple of ways I could do round X+ y but uh you know I'd actually kind of prefer to break this now out into two lines I don't have to and reasonable people here might disagree but I'd like to revert to a scenario where I'm printing Z so that I can just a little more clearly to myself to others say Z equals the rounded result of x + y it's not necessarily the better way to do it but I'm a little more comfortable with breaking out my thoughts one at a time especially if I want to start commenting of these chunks of code all right let me go down to my terminal window now and run python of calculator. Pi what's X let's do 1.2 again then let's do 3.4 and now it was previously 4.6 but now it's been rounded up to the nearest integer which of course is going to be five all right what if I wanted to change this a little further what if I wanted to support maybe really big numbers big numbers irrespective of rounding let's just do something like this let me go ahead and run python of calculator. Pi again and let me just add 999 + 1 and notice I don't have to type decimal points even though I'm converting to float my program will just allow me to type decimal points but I don't need to oblige the answer of course here should be and is in fact 1,000 whether or not we round so that's just arithmetic with integers here but in uh the us we tend to format long numbers by putting commas uh after or before every triple of digits other countries flip it and they use periods and commas instead that's a system setting you can change that on your own Mac or PC or device for python or any language but for me I'm using the uh us approach here which is periods for decimal points and commas for separators what if I wanted this to be outputed as 1 comma 0000 just to make it a little more clear that it's 1,000 and not something like 100 that's even more useful when it's like 1 million 1 comma 00 comma 00 0 wouldn't it be nice if we could automatically output those numbers as well well it turns out that we can there is a way using python to actually specify that we want to include commas like this and here we have an opportunity to bring back our old friend the F string first let me do something that's not that productive first let me do this let me print out the value of Z but wait a minute I can't just say quote unquote Z because that's literally going to print Z on the screen so let me wrap it with those curly braces like I did before but that two was not enough I literally needed to add an F at the beginning of my string to tell python that this is an F string a format string that now is going to print out not very interestingly just the value of Z itself so that I'm going to Great Lengths just to print Z when really I could have just passed Z as the sole argument but just to ensure that I haven't broken it let's do this again 999 + 1 enter okay it's still a th so I didn't make anything worse but notice and this syntax is unfortunately a bit cryptic notice that I can actually do this I can put a colon after the Z and I can put a comma thereafter this looks very cryptic admittedly and even I have to constantly look things like this up in the documentation to remember the syntax but here let me run it again python of calculator. 9991 and now notice that the number has been automatically formatted for me if I were in a different country or local I could abs absolutely override this to use periods instead of commas or vice versa but in this case here it's just happening for me automatically so there too we see a hint of what it means to really format a string there's even more power more powerful capabilities built into that all right let me pause here to see if there's any questions now on floats on rounding or on this use of f strings yes so I have a question so when using floats um is it like a cap to how many decimal points you can have a really good question so floats yes and this is a problem we'll revisit before long floats cannot represent numbers infinitely precisely in a nutshell because computers only have so much memory they only have a finite amount of memory you and I only have a finite uh amount of Hardware inside of the computer so at some point they're going to have to Round right now I'm rounding automatically effectively computers will eventually have to do that for us but we'll see that as a fundamental problem before long allow me to turn back just for a few final examples on Flo before we introduce a few final examples that allow us not just to use functions but to make our own let me propose that we also try our hand at a bit of division here let me propose that we modify this calculator now to still take a couple of floats but let's now just do something a little simpler than uh a little different from this just doing x ided y and let me go ahead and get rid of my format string and just keep it simple for now printing out Z instead and what are we going to see here well just some simple division so python of calculat Pi let's do something like 2 / 3 and of course I get 66666 and to Ethan's question a moment ago it does seem to be finite it's not rounding in a weird way here but I only seem to see so many digits that's a uh an inevitability of using a float in this way by contrast just so you know integers nowadays in Python can be as big as you want them to be unlike other languages there is no upper bound on how big an INT can be now in Python but there is a bound on just how precise prise a floating point value can be all right now that I've got some simple division working here let's go ahead and round this it would be nice to round this really long number 6666666 and so forth to maybe just two decimal places we've seen how to do this with round though at least in its documentation let's just round this not to the nearest int by passing in just x / Y which is one argument once the math is done inside of the parenthesis I don't want to pass in just one argument I want to pass in two so that I can specify n digits number of digits which recall was the second parameter for round let me go ahead and run python of calculator. Pi I'll do the same thing two and then three 67 so here too we see a way of rounding now not just to a nearest integer but to a nearest number of digits but there's another way to do this here and in fact this evokes our our uh F F string example again let me go ahead and change this suppose that you didn't remember the round function or for some reason you didn't want to use it you instead want to just use a format string well let's go there let me do quote unquote Z but let me surround it with those curly braces let me add the F at the beginning and again this is not interesting yet this is just going to print out Z but I'm adding a lot more complexity to turn it into an F string but notice I can do something else after my variable name after the colon if this were going to be a big integer I might want to use a comma like before to separate each triple of numbers with commas but I don't I'm going to use a different sequence uh of characters I'm G to say 0 2f and this too is one of these very cryptic things I have to constantly look up because I forget if I don't use it that often so don't be intimidated if this looks especially weird but this is according to the documentation the way you specify using an F string how many digits you want to print so let me run this version of the calculator type in two and then three we get the exact same thing but again this is just consistent with my claim that in program we can so very often solve the same problem in multiple ways this is just now the F string approach to that very same problem all right which one is better it depends in this case they're pretty equivalent you could imagine though it being useful to use a function sometime so that you can pass in an argument like n digits as that second argument or you can imagine just deciding in advance that you want Point 2 and then writing it like this let's transition now from focusing on string and on integers and on floats to focusing now on functions themselves we began today by focusing on how you can use functions that come with python but wouldn't it be nice if you could invent your own functions especially if to our Point earlier you find yourself solving the same kind of problem again and again it's nice that python comes with the print function because it's really useful to be able to print things on the screen but wouldn't it be nice if you could print specific things on the screen by just calling your own function well let me propose that we do this let me go back to VSS code here and let me propose that we go back to hello.py I'm going to reopen hello.py where we left it before and I'm going to go ahead now and propose that we consider how we can start improving this further by making our own function I have written so many programs today that just say hello and each time I'm using print but wouldn't it have been nice if from the beginning of today we could just call a function called hello that just says hello for us now the authors of python years ago didn't think that we a special function just to say hello but I would like that to exist I'm saying hello so many times I just want to be able to call a function hello so I'm going to start from scratch here I'm going to delete all of my code from earlier and I'm going to pretend for the moment that a function called hello exists and I'm going to do just as I did before I'm going to get the user's name with the input function asking what's your name question mark and now I'm going to call a function hello and then I'm going to print out the user's name now I will admit hello doesn't exist so bad things are about to happen but let's see what let me go down to my terminal window let me run python of hello.py I think the first Line's going to be okay because that worked before and indeed it's prompting me for my name so let me type in David the second line of code is apparently calling a function that looks like it's called hello because why is it a function it has a parenthesis and a Clos parenthesis immediately after it and that's what every function we've used has looked like but Python's not going to recognize this one when I hit enter now I get a name error name hello is not defined did you mean help I didn't although it's opportune that's what I need at this point is some help but I am encountering this error because why the function just doesn't exist so how do I make this function exist well I need to create it myself using this keyword defa defa for Define so here too just as stir is short for string and int is short for integer def is short for Define if and when you want to Define create invent your own functions you can do so using now this keyword in Python so let me go back to my code here and let me propose that we Define this perhaps in this way at the very top of my file I'm going to first take a moment to define a function called hello using def hello open parenthesis close parenthesis colon what this means now is that python is going to treat every line of code that I IND underneath this one as the meaning of this new function hello So Def is important as is the space I get to choose the name of the function and I'm choosing to call it hello the parentheses with nothing inside means that this function at the moment is not going to take any inputs no arguments there too the colon means stay tuned for some indentation everything that's indented beneath this line of code is going to be part of this function it's going to be a super short function one line of code it's just going to print out quote unquote hello but now on lines one and two I have invented my own function hello notice these dots that have now magically appeared here this is just a setting of my text editor VSS code in this case that's just making super explicit to me that I've hit the space bar four times or equivalently the Tab Key once which is converted automatically to four spaces generally speaking I'm going to need to make sure that all of my indented code lines up now so that python knows that it's all part of the same thing but it's easy in this case cuz it's just a single line but now thanks to lines one and two the function hello will absolutely exist when I'm ready to use it on line six so let me go down to my terminal window and run python of hello.py enter here comes my name again and now when I hit enter I now see hello David all right we've kind of regressed though right this is not nearly as pretty as it once was I think we can probably do better than this by improving things further why don't we consider though how we might say parameterize the same function that is to say can we customize hello to maybe take the user's name as input so that we can say not only hello but the person's name all on one line all in one breath well I think we can do this let me propose that we do this as follows let me go ahead and up in my code let me inside of these parentheses let me come up with my own parameter name I have complete Choice here and I'm going to say that the name of of my parameter will be the word two why because I want my function to sound like the verb it represents hello but who do you want to say hello to well I'm going to call my parameter for this function to just CU in English it kind of sounds nice to me hello to who do you want to say hello to that's why I'm calling this parameter to instead of something simpler like X or Y or Z all right well what do I want to do with the word to well I can do a couple of different things we've seen like so many different ways to implement hello let me just add a comma there for grammar's sake and then let me put the word to after that as the second argument to the function hello there's other ways we can do this and we've seen so many but this one looks a little clear to me I'll say what's going to happen next well I don't think I need this extra print line here I think what I'm going to do is this I'm going to go ahead here and print out not the person's name manually I'm going to inste instead say hello parentheses name so what am I now doing on lines one and two I'm defining my very own function called hello but this time that function has been designed to take a parameter a single parameter as input and I'm using the value of that parameter which I called two to plug into print so that I see not only hello but also that person's name what am I doing on line five same as always I'm just getting the user's name line six I'm not only calling hello I'm passing as input the name variable as an ARG argument so that that's what gets passed into hello and what's Happening Here is essentially this even though the variable is called name here when the function itself is called the computer assumes that that same value is now called two so name is essentially copied to another variable called two so that in the context of hello I can say hello to that variable instead and we'll see in a moment what happens if we don't keep those uh straight let me go ahead and run python of hello.py enter what's your name and now I'm crossing my fingers enter there we go we're back in business but now I have my own custom function called hello that's allowing me to say hello to a specific person and here's where now things can get really fancy what if you wanted your hello function to say hello to someone specific but you know what if you don't know who you want to say hello to you want to say hello to the whole world you can give parameters default values we've seen that recall that with print there was a default value for sep for the separator there was a default value for end the line ending we can do that too and here's the syntax if you want the value of this parameter by default if not provided by the programmer to be equal to quote unquote world you literally do that in the same line you're defining the function and I'll admit it's starting to look more cryptic but I'm still just defining a function called hello it takes a parameter called two but I'm assigning it with the equal sign a default value of quote unquote world just in case the programmer doesn't call hello with an argument and we can see this here let me change my code to use hello in two ways on line five I'm going to very simply call hello no arguments then on line six I'm going to get the name line seven I'm going to call hello with an argument so you'll see hello now being used in two ways let me go ahead and run python of hello.py I'll type in my name oh interesting notice I already see hello world but that's expected because line five happens before line six but once I type my name now the program is going to be a little more polite and say hello to me personally so there too we see with relatively simple but new syntax how you can Implement functionality very similar in spirit to what the print function gave us automatically now you have control over doing that yourself but let me now make this point too one of the whole points of defining your own function is one just to avoid having to repeat yourself again and again you don't have to actually keep Reinventing the wheel and keep using the print function again and again and again if you just want to say hello wouldn't it be nice now if I could kind of move this code that I wrote for defining the hello function and just to be dramatic I'm going to hit enter a whole lot of times 50 lines down and put my definition of hello way further down in this file why well just in the spirit of out of sight out of mind because if I now rewind to the start of my program now you can sort of take for granted that oh hello is a function why because it's there on line one and it has an open parenthesis and a closed parenthesis which up until now has meant call this function and then on line two we're getting a variable from the user by typing in their name and then we're calling hello passing in that value well at this point I can just take for granted that hello exists even if it's way down further in the file or as we'll see in future weeks even if it's in a different file altogether but there's a problem here and let me go ahead and run this version of hello.py notice that as soon as I run The Interpreter python of hello.py I see a name error name hello is not defined again did you mean help well again fitting I do need some help here but I didn't mean to call the function help the problem here though is that python is just taking me literally I have defined my function hello all the way down here but I'm trying to use it way up here and that's not allowed Python's interpreter is going to take you literally and if you use a function it must already exist by the time you are calling it so how do I fix this well apparently I can't do that I have to Define any functions I want at the very top of my file but that too could get me into a bit of trouble eventually because if I constantly have to define a function above where I want to use it you're kind of writing code in Reverse you're constantly writing functions up here up here up here as opposed to like writing your code logically top to bottom so let me fix this in a more standard way which is to do this generally speaking you do want to put the main part of your code at the top of your file and in fact I'm going to go so far as to Define my function called main it's not a requirement but it's indeed a convention and this just connotes to the reader that this is the main part of my program I'm going to get rid of my empty hello call now and only pass in one version with hello name and then down here a couple lines further down I'll actually Define my hello function unfortunately now that I've reordered the functions in this way by putting the main part of my code at the top and hello at the bottom so that my logic kind of flows top to bottom if I go ahead and run python of hello.py enter nothing whatsoever happens if I do it again nothing whatsoever happens well why in the world is this well just because I've defined a function called Main and I've defined a function called hello doesn't mean that I've actually called that is used either of them yes I'm using hello in side of main but no one is telling python to actually use or call Main so in order to tidy this up the last thing I need to do in this file it seems is actually call my main function and in fact by calling my main function in this way it gets me out of trouble because now I'm defining main first but I'm not calling hello yet I'm defining hello next but I'm not calling hello next I only at the very end of this file call Main which has the effect of running this code up here which has the effect of running this code down here and it allows me therefore to organize my file and Order My functions in any way I want including main at the very top and solving ultimately that problem of python not knowing what's going on now it's important to note that I defined my function hello as taking an argument to and then I passed into that function the value of the variable that I wanted to say hello to that is the variable called name because suppose I had done something a little bit differently suppose that I hadn't defined hello is taking an argument so I just remove mention of two and its default Value World and I go back up to my main function and I just call hello itself without passing in any arguments and now let me go ahead and make one more change one more mistake technically let me go ahead and just try to naively print out the value of name in the hello function so now to be clear in my main function on line two I'm defining my variable called name and assigning it the return value of the input function from the user I'm then just calling hello in my hello function which now no longer takes any arguments I am calling print passing in hello comma and then immediately passing in name the variable into which I got the user's input but the catch is that name exists now only in Maine and so watch what happens when I try to run this version of the program with python hello.py I hit enter I'm prompted for my name DAV ID enter and ah a name error name name quote unquote is not defined so it turns out that this is actually an issue of what's called scope scope refers to a variable only existing in the context in which you defined it so in so far as I Define this variable name in my main function I can only use that variable in my name function I can't use it as I've tried to here in my hello function it doesn't exist in that so-called scope and so this is why now if I rewind and undo all of those changes you'll see that I'm deliberately passing main from my main function into my hello function and now in the hello function it technically has a different name it's called two in that context but that's fine it's completely up to each individual function to name its own variables or name its own arguments but this is a way now that I'm handing to the hello function the value of that variable so it can be printed by hello as well and there's one final flourish we can add here now that we've implemented hello you'll notice that hello only has a so-called side effect it only prints out something to the screen well what if I also want my function to not have a side effect per se but actually hand me back a value recall that the input function returns a value the string that the user typed in recall that the int function returns a value the float function returns a value that was passed into it well you can use one final keyword here literally return to return a value explicitly yourself in fact let me go back to VSS code here and I think we'll return our attention to calculator. Pi and see if we can't Implement one other version of calculate calculator. pi that actually has our own function that even returns a value so I'm going to go ahead and open up uh calculator. pi and I think this time I'm going to throw everything away as before and I'm just going to start practicing what we're preaching here Define a function called main which is now going to be the main part of my function let's go ahead and now declare a variable called X and assign it to the converted version of the user's input after asking them what's X so again a line of code quite like we've done before and suppose now that what I want to do is square this value I want to take the number that the user typed in and raise it to the power of two so 2 squar would be 4 3 squar would be 9 4 squar would be 16 and so forth well how do I go about implementing a function literally called Square which actually doesn't come with python built in well let me assume for the moment that it does exist and let me say something like this let me go ahead and say that uh printing how about uh X2 is comma square of X so what have I done I've defined a function called Main and I've implemented two lines the first of these lines prompts the user for a value X and converts it to an INT and stores it in a variable called X on line three I then say x^2 is and then I pass a second argument to the print function whatever the return value is of a square function but Square doesn't exist and I'll show you this here if I now call Main at the bottom and I run python of calculator. Pi I'll see that X is two and then I see a whole bunch of Errors a name error name square is not defined so this isn't a typo here it's just the function doesn't exist but I think I can make it exist here let me go ahead and Define another function called Square this one's going to take in a number and I'm going to call it generically n as many a programmer would just to represent any old number and then what do I want to do in order to square n well a numbered squared is really just itself times itself so I'm going to do this n * n but it's not enough just to do the math yourself n * n you're going to have to return the actual value n times n and that's our new keyword here when I now do this Watch What Happens python of calculator. Pi enter X sh say shall be 2 x^2 is 4 let me go ahead now and say x is now three X2 is now 9 so I've implemented my very own function that Returns the square of a value and because I'm using the return keyword that ensures that I can pass the return value of this just like the return value of input or int or float to another function like print instead and here too there's going to be so many ways to solve the same problem I can actually raise n to the power of two we've not seen the syntax before but if you use two two asterisks like this two stars that raises the thing on the left to the power on the right or it turns out there is in Python a function called pow for raising something to the power that takes two arguments the first of which is the number the second of which is the exponent so there too there's just so many ways to actually solve that same problem as well so ultimately what we have we done here we first introduced functions these or verbs many of which come built into python that you can just use in your own code we then introduced variables via which you can store those return values and then maybe do something more with it at the end of the day too you now have the ability to create to invent your own functions to solve simple problems like hello or in the weeks to come much more sophisticated more challenging more fun problems as well [Music] [Music] all right this is cs50's Introduction to programming with python my name is David men and this week we focus on conditionals conditionals or conditional statements in Python and in other languages are this ability ility to ask questions and answer those questions in order to decide do you want to execute this line of code or this line of code or this other line of code instead they allow you to take the proverbial Forks in the road within your own code logically so how might we go about making some of these decisions well it turns out that python comes with a lot of built-in Syntax for instance here are just some of the symbols you can use in Python to ask questions admittedly mathematical questions but we'll start there if only to keep the example simply simple early on this first symbol as you might know for math represents greater than the second symbol might not look too familiar because we usually write it all as one thing on a piece of paper but on a keyboard if you want to say greater than or equal to you'd use this symbol Instead This of course means less than this means less than or equal to and this one's a bit of a curiosity we've seen in our look at functions and variables how we were able to assign values to variables using a single equal sign but that equal sign didn't repres represent equality it represented assignment from right to left that's great because it solved that problem but it kind of left us in a bit of a bind because how do we now compare two things left and right well in Python and in many languages you actually use two equal signs so two equal signs represents equality comparing the thing on the left and the right one equal sign as always represents assignment copying the thing from the right to the left lastly this last symbol represents not equal to so the exclamation point or Bang uh followed by an equal sign means not equal to some value next to it well to ask the questions using these symbols or any others we're going to need another keyword in Python and that keyword quite simply as in English is if you can ask questions in Python code along the lines of if the answer to this question is true then go ahead and execute this code for me so let's go ahead and write some of these examples here I'm going to go over to VSS code and let's go ahead and create a program for called compare. the goal of which is simply to write code that compares values and makes decisions based on those values let's go ahead and type code of compare. py in order to create a brand new file called compare in which we'll start to express some of this logic all right well what do we want to compare suppose we want to compare for the sake of discussion just a couple of integers but we'd like those integers to come from the user so that we can make uh decisions based on numbers we don't know the values of in advance well let's go ahead and do this as we've done in the past let's declare a variable like X let's assign it equal to the return value of the int function and pass to the int function the return value of the input function asking the user a question like what's X question mark As we've done in the past let's do this one more time with Y asking the user for the value of y and again uh converting that ultimately to an INT as well so at this am of the story we have two variables X and Y Each of which has values and ideally we should be able to now compare these values so suppose I want to make a decision based on the values of these variables I'm going to use the keyword if and I'm going to use some of those mathematical symbols to actually ask the question itself so how about this if x is less than y then let's go ahead and just print as much Out quote unquote X is less than y so this isn't a very interesting program yet I'm literally just stating the obvious based on the math but it's allowing me to introduce some new syntax and exactly what is this syntax well it's this not just the keyword if which I've added here at the start of line four but then I ask my question here x less than y x is one variable on the left Y is one variable on the right and of course the less than sign is expressing the mathematical question I have what I've highlighted here is technically called a Boolean expression a Boolean expression named after a mathematician named bull is simply a question that has a yes or no answer or technically a true or false answer and that's nice because if there's only two possible answers it's very easy for me and in turn the computer to make a decision do this or don't do this thing now notice if you come from other languages you might notice that I have not typed any parentheses they are not in fact necessary at least in this case in Python but I have typed a colon at the end of the line and even more importantly at the next line I have begun my line with some indentation hitting the space bar four times or just hitting tab once which will automatically be converted to the same that indentation is what tells python that line five should only be executed if the answer to line Four's question is in fact true so if x is less than y that phrase will be printed thereafter well let's add a few more lines of code how about another question If X is greater than y then let's go ahead and print that X is greater than y and let's do one final question if x equals y then wait a minute what have I done wrong here right a good eye here I don't want to assign y to x if x equals equals y is how I express equality let's go ahead and print out X is equal to Y so I now have a uh three conditions if you will one question asking X less than y one asking X greater than y one asking xals equals y let's run the code well down here in my terminal window I'm going to run python of pair. pi and hit enter what's X let's go with one what's y let's go with two this should of course execute that first line of code and tell me indeed that X is less than y exactly as I would expect there well what just happened though in code well let's take a look perhaps at this same code uh visually particularly if you're a more visual learner this I dare say is what just happened so what we're looking at here is a a flowchart it's a diagram of this program's logic and more technically it shows the program's control flow that is the ability of you and code to control the flow of a program generally from top to bottom in fact let me go ahead and zoom in on the top of this flowchart and you'll see an oval at the very top that says quite literally start that is irrespective of what shape or layout the diagram is is where your own thinking and logic should start when trying to wrap your mind around this program notice that there's an arrow from start to this diamond shape and inside of that diamond is a question a an expression X less than y and this shape just means based on the answer to that question go left or go right specifically go left if the answer is true or go right if the answer is false well the inputs I typed were one and two respectively for X and Y so of course one is less than two so that's why my program printed out quote unquote X is less than y but recall the code the code then proceeded to ask two more questions is X greater than y is x equal equal to Y well the flowchart depicts those questions too notice that no matter whether the question had an answer of true or false the arrows both converge back down to this second diamond shape here and that second diamond shape asks the second question X greater than y that too has a true or false answer so we go one way or the other but if x is 1 and Y is 2 then no the answer is false one is not greater than y so so logically in the flowchart you follow the false Arrow this time and notice along that false Arrow you don't print anything this time that's why we only saw one print out on the screen now there was still a third question and this flowchart captures that as well the third Diamond asks x equals equals y now that to has a false answer in this case because one of course does not equal equal Y and so we again follow the third false Branch here and that leads us of course to stop and stop just indicates that's it for the program so think that's correct and that particular flowchart does happen to represent the actual code that I wrote so it's correct it does what it's supposed to do it answered the question correctly by printing on the screen X less than y but what is perhaps poorly designed about it let's make this first distinction it's not enough necessarily for the code that you write to be correct and do what you intend longer term especially as our programs get longer and more sophisticated more complicated we're going to want them to be welld designed too thoughts on in what way this program is arguably not welld designed even though it's correct let's see here uh khed if I'm saying that right your thoughts too many ifs I think is getting repetitive we can make our code more concise maybe yeah it seems a little repetitive I'm asking if this if this if this and yet logically I should know the answer to some of those later questions once I figure one out and in short if you look at this diagram here notice that no matter matter whether I go left or I go right I'm always asking three questions no matter what all of those arrows lead to the first the second and the third Diamond so I'm asking three questions no matter whether any of those answers are true or false well how might I go about improving this well let me propose that we introduce another keyword to our python vocabulary namely L if and this too is kind of a succinct one it's a conjunction of else if in English which allows us to ask a question that takes into count whether or not a previous question had a true or false answer well what do I mean by that well let me go back to my code here and let me propose that we now improve upon this here by asking ourselves ultimately how can we ask fewer questions and let me go ahead here and propose that instead of asking if if if let's make these conditions potentially mutually exclusive that is to say don't keep answering questions once we get back a true answer so I'm going to change my code up here as follows instead of asking if if if I'm going to say if x less than y l if x greater than y l if x equals equals y so I'm going to implicitly just like an English take into account that I'm only going to keep a asking myself these questions if I haven't yet gotten a true response think about the logic here the English if x is less than y on line four print out out X is less than y well if that's the case you're done logically because if the English is saying if x less than y else if x greater than y those are going to be mutually exclusive if the answer to the first question is true you don't have to keep asking questions to which you already logically know the answer so let me go ahead now and run this program and I think the behavior is going to be the same python of compare. Pi what's X let's do one what's y let's do two x is less than y now honestly I didn't really notice a difference when I ran the program and honestly my Mac my PC my phone nowadays are so darn fast that these kinds of improvements aren't going to necessarily feel any faster until we're writing bigger faster programs but it's laying the foundation for writing better code longer term now what is the Improvement I've just made well if previously my diagram looked like this which was problematic in so far as I was asking three questions no matter what even if I already figur out what I want to print on the screen this new version of the program that says if L if L if might look a little something like this instead now it got a little wider that's just because we drew the arrows to be a bit wider here but let's focus on just how many questions are getting asked let me zoom in at the top as before and let me propose that we note that the start oval is at the very top and it's asking us to ask one question first X less than y is one less than two but notice here let me zoom out if one is indeed less than two we follow this long longer Arrow the down Mark true we print out quote unquote X is less than y but then we immediately follow this next arrow down to the icon that says stop so that's what's implied by doing if L if L if if we get back a true answer right away to that first if we're going to print out X is less than y and then stop we're logically at the end of the program so this picture is just representing graphically what the code is actually doing but suppose I typed in something else suppose that my code actually ran and I typed in two for x and one for y that is to say the answer to the first question is now false but the answer to the second question is now true because of course uh one uh two is greater than one well let's go back to the diagram same as before we start at the very top where it says start the very first question up here now X less than y is an answer of false because no two is not less than one so we follow this arrow to the next question this diamond is X greater than y well yes 2 is greater than 1 so now we follow this left Arrow which is true we print out quote unquote X is greater than y and then stop so what's the Improvement well in the first case we got lucky and we only had to ask one question and boom we're done this time we had to asked two questions but then boom we're done only if x happens to equal y do we actually find our elves logically getting all the way down to this final L if in my code and pictorially only if x is equal to Y do we find ourselves going all the way down to the third Diamond the third question asking is it equal to y or not now hopefully the answer at that point is not false we've included a false Arrow just so that the program itself is well defined but logically we shouldn't actually be getting there anyway because it's got to be less than or greater than or equal to in this case well let me pause here to see if there's any questions now either on the code version thereof here or on this diagramming of that very same logic questions here on this control flow uh AR we supposed to put an else at the end ah a good question and yes so that's going to be my my third and Final Approach and if you don't mind let's pivot there right away identifying a third keyword that indeed exists in Python that allow ows us to be even better at expressing this logic to design this program even better and that's going to solve a particular problem so if I take us back to our code here notice that what I've highlighted earlier L ifx equals equals y it's not wrong to ask that question in fact if you're trying to be especially thorough it makes perfect sense to check if x is less than y greater than y or equal to Y but why don't I need to ask this third and and final question we don't need to ask if x is equal to Y anymore because logically if the two conditionals evaluate to false there is only one um conditional that will evaluate to true and that is X is equal to Y exactly if we're all pretty comfortable with math and comparisons here of course X is either going to be less than y greater than y or equal to Y but once you rule out the first two scenarios logically it's got to be the case that X must equal y if it wasn't the case that it's less than or greater than so hope propos that we use this other keyword else and how do we use this well exactly as we might in English let me go back to my code here and instead of bothering to ask the third and final question let's not ask a question at all let's just have this catchall so to speak a final line of code that says else just assume that X is equal to Y therefore printing it as well so what's the upside of that my code is still going to work exactly the same and again my computer's so darn fast I don't even notice that it's working even faster than it was before but we would notice these kinds of things if we were doing a lot more work a lot bigger programs here but let me run python of compare. piy let's do for instance one and two still works for that let's do two and one still works for that let's do one and one and it indeed now works for that but in these cases now let's consider the path we just went down previously our diagram when we had if L if L if in place looked a little something like this and notice that again we might have asked one question or two or worst case three whole questions but we can do better than that using else as hope proposed we can Whittle this diagram now down to this and even though it looks like the diagram is getting bigger notice that it's having fewer uh building blocks inside of it there's fewer arrows and there's fewer nodes in this picture let's start at the top now start leads us to the first question still X less than y if the answer is true great we can say as much X is less than y and we can stop if it's not true if it's false we can ask the next question X is greater than y true or false if it is great we can print X as greater than y and stop else if it's not the case that X is greater than y the answer is false we can just immediately logically say x is equal to Y we don't have to add the third question at all we can just immediately conclude there so what's the implication here you can see with these pictures a relative decrease in the comple it of a program the first one was very long and stringy with lots and lots of questions unnecessarily ultimately the next one got a little shorter and this one's even shorter still and again the fewer lines of code you have the less likely you are arguably to make any mistakes the easier it is for other people to read and so generally this readability this simplification is indeed a good thing well let's go ahead and add another piece of uh capability into Python and that's this one here just like in English where you can ask this question or this other question you can say the same thing in Python using literally this word or so let me go back to my python code here and let's propose how we might ask a couple of questions at once this time perhaps this time considering how we might ask not whether or not it's greater than or equal to and caring about the precise answer let's take a a coarser approach here and let's just try to determine is X greater is x equal to y or not well let me go ahead delete some of this code and change the question we're asking let me do this well if I care about whether it's equal or not let's check the possible scenarios if x is less than y or X is greater than y let's go ahead and print out X is not equal to Y now why is that no pun intended if x is less than y well it's obviously not equal if x is greater than y it's obviously not equal so we can conclude X is not equal to y so if we instead want to make sure that it is equal to we can just use uh hopes else using print quote unquote X is equal to Y and again why is this well if x is less than y or X is greater than y they're obviously not equal otherwise logically they must be equal in fact so let's run this let's go ahead and run python of compare. Pi what's X One what's Y 2 okay X is not equal to Y let's do it again but two for x one for Y X is not equal to Y and one third time how about X is 1 and Y is One X is now equal to Y now if we want to compare that visually too let me propose that the picture looks a little something like this and again this is the exact same thing logically but it's a pictoral representation thereof what's the first question well if x is less than y well then we follow the true arrow and we say quote unquote X is not equal to Y and then we stop but what if X is not less than y what if it's greater than y what if it's 2 and one respectively then the answer to x less than y's first question is false so we go here we ask the second question because of the or and that asks is X greater than y if so notice this we can kind of reuse some of the same parts of this picture and just say X is not equal to Y we don't need to add arrows and add boxes unnecessarily we can reuse lines of code uh picture parts of the picture just as we have lines of code and then we stop lastly we have the following if we know that X is not less than y we know that X is not greater than y it must be the case that x equals y we don't need to ask a third question another diamond we can just immediately print as much and then say uh stop as well well what could I do here I bet I could improve this code slightly and if we really want to be nitpicky I would argue that this is now really just a minor refinement but it's a good habit to get into thinking about could my code be better could my code be simpler could I improve this code further it's subtle but could I improve the design could I ask fewer questions could I tighten it up so to speak what do folks think you can ask if x is just equal to Y then if you print x equal to Y else X is not equal to Y perfect recall one of the other symbols we saw on the available list earlier we can check not just less than or greater than or equal to we can literally ask the question is it not equal to why are we wasting time asking if it's less than or if it's greater than well if all you care about is is it not equal I think we can do exactly that let's just ask the one simple question we do care about and so let me go back up here and let me just say not both of these questions let's get rid of the or let's just say if X is not equal to Y then go ahead and print X is not equal to Y and that too I think is going to work exactly the same but the picture now looks a little bit different notice that this was our flowchart earlier that represented that same logic and there's a bit of complexity you got to go left you got to go right based on the answer to these couple of questions if we now take into account what this version of the program looks like it's even simpler perhaps the simplest one we've seen yet when we start off the program we ask just one and only one question is X not equal to Y and if so true we go ahead and print out X X not equal to Y if the answer is false then of course it must be equal to Y so we say that instead and if we really want we could invert this if I go back here to my code and if for whatever reason you just prefer to think in terms of equal or not equal as opposed to not equal or equal it's really uh up to you we could change this to be equals equals but I'm going to have to change my print statements to be in the opposite order so let me go ahead now and reverse these two here and move the second one first and the first one second so now when I execute this code I'm asking still just one question so it's still just as good just as succinct but now the diagram instead of looking like this is going to change the not equal to equal equal and we just need to make sure that we print out the right thing accordingly and again here too just as the code is getting a little more compact a little more compact with fewer and fewer characters so are these diagrams these flowcharts capturing the relative simplification of each of those programs too all right let me go ahead and pause here to see if there's any questions now on any of these versions of code yeah I have a couple of questions uh what if indentation is not used uh if indentation is not used your program will not work so python is a little different from a lot of languages in that it enforces the indentation requirement uh some of you who have been programming for years might not necessarily be in the best habit of indenting your code properly and one of the features arguably of python is that it makes you indent your code or it will not just work and I think did you have one other question uh yeah uh is the colon necessary is the colon necessary yes the colon 2 is necessary so with python what you see is what you get here and indeed it needs to be indented and the colon is necessary python does not use in the same way by Convention as C and C++ and Java curly braces to canote blocks instead it relies indeed on this indentation well let me propose that we introduce one other keyword here in Python to see exactly how we might combine additional thoughts and that's going to be literally the word and a conjunction of one or two or more questions that we might want to ask at once and let me propose here that we explore this kind of logic by way of another program Al together in VSS code whereby I'll go ahead now and create a new program say called grade. Pi let's consider exactly what grade a student should get based on their score on an exam or a test or a quiz or some other assignment like that I'm going to go ahead and run code of grade. py to give myself a new file and I'm going to go ahead and start by just getting the user score again on some assignment or test or the like and I'm going to store it in a variable called score equal the return value of the int function which is going to convert whatever the user's input is when prompted for this score so again the user should just Oblige by giving me a number like zero or one or two or or hopefully much higher than that like 997 98 99 100 assuming the test or assessment is out of 100 percentage points now how could I go about assigning a grade to the student score well in the US it's very commonly the case that if you get between a 90 and 100 that's an A and if it's between an 80 and a 89 it's a b if it's 70 and 79 it's a c and so forth all the way down to F which should be e but we'll see that there's a bit of a jump so how might I exess this well I can use conditionals and I can ask a few questions and then print out the student's grade accordingly so let me express it like this if the student score is greater than or equal to 90 and the student score is less than or equal to 100 so it's in that range let's go ahead and print out that their grade shall be in a because they're in the 90s above grades range L if the score is greater than or equal to 80 and the score is less than or equal to say 89 but here I have some options logically I can actually express myself in any number of ways and maybe just to be a little cleaner I'm going to say in score is less than 90 so I'm using less than instead of less than or equal to so I'm making sure that their boundaries between these grades are correct then I'm going to go ahead and give the student a b if it's in the 80s L if score is greater than or equal to 70 and the score is less than 80 I'm going to go ahead and give them a c l if the score is greater than or equal to 60 and the score is less than 70 I'm going to go ahead and give them a d and here's where it's a little anomalous at least in some schools here else I'm going to go ahead and give them uh an F so we're skipping e Al together and we're going to give an f instead for the grade so that's the catchall and I think logically I've gotten this correct at least based on where I went to school growing up such that it's going to give an A or a b or a c or a d else it's going to ass assume that you got an F well let's try just a few of these here let's run python of grade. Pi my score is let's let's start strong 100 all right I got an A didn't do as well the next time maybe it's a 95 still an a starting to slip further so I got an 89 the next time that's now say a b and let's say I really had a bad week and it's now like a 71 that's now A C or I didn't even submited at all that's a an F Al together all right so it seems to work that's not really an exhaustive test but at least based on some sampling there my code seems to work as I expect but let's see if we can't tighten this up it's not wrong it's correct and indeed according to my own specifications I dare say this code is correct but can we tighten it up can we reduce the probability of bugs now or down the line can we increase the readability of it and can we increase the efficiency of it can we get the computer to have to answer fewer questions and still get the same result well let's see what we might do let me just kind of switch things up if only to demonstrate that we can use these symbols in different ways is I could say as I've done if score is greater than or equal to 90 but I can actually do this I can flip it around instead of saying greater than or equal to let's say 90 is less than or equal to score and here let's say if 80 is less than or equal to score and here 70 is less than or equal to score and then lastly 60 is less than or equal to score so it's the same thing logically I'm just kind of switching things around just like you could do on paper pencil if you really wanted but now notice this trick and this is not possible for those of you who have programmed in C or C++ or Java or other languages notice what I can do here is actually combine these ranges notice that I'm asking two questions two Boolean Expressions is 90 less than or equal to score and is score less than or equal to 100 well python allows you to Nest these things like this and chain them together and just like you would on paper pencil the real world you can encode in Python do this which is just a little cleaner right it's tightening up the code a little bit it's fewer keystrokes it's faster to type it's easier to read moving forward so that's arguably better as well so that's one Improvement it's largely aesthetic in this case it's still asking the same number of questions but it's doing it a little more succinctly still well what what more could I do here next well you know what each time I'm deciding these grades I don't think I have to ask two questions I I don't have to ask is it greater than 90 and less than 100 is it greater than 80 and less than 90 if I kind of rethink my logic I can maybe do this better still let me propose that we simplify this further and just do this if we know the input for the moment is going to be within zero and 100 we can make some assumptions we could say something like if the score is greater than or equal to 90 well the student gets an A L if the score is greater than or equal to 80 the student gets a b l if score is greater than or equal to 70 they get a c l if the score is greater than or equal to 60 they get a d else they get an F so what have I done here well instead of asking two questions every time checking the lower bound and the upper bound of that range I'm kind of being a little more clever here by asking if the score is greater than 90 well they've obviously gotten an A or better if your score is greater than A8 well you either deserve an a if it's really strong or a B if it's just above 80 but because of the if L if logic we've already checked is the student score greater than 90 and if it's not then we're asking the question well is it greater than 80 so you implicitly know it's somewhere in the 80 to 89 range else you know it's in the 70 to 79 range else it's in the next range down so it's a minor optimization that allows us to ask fewer questions but again it's making the code arguably a a little more readable certainly more succinct and then hopefully more maintainable longer term any questions then on these types of changes and this type of logic with our code uh what if we don't use l if at all what if we uh write the code in F yeah so that's a good question because it's actually going to have an unintended effect here let me get rid of the F temporarily and just focus on a through d if we revert to where we began today's story with conditionals saying if if if if now our cleverness here of using broader strokes and not using in upper and lower bound ranges is going to come back to be a downside let me go ahead and run python of grade. Pi and suppose my score is uh 95 I am so darn excited I want my a but nope I just got an A a b a c and a d so logic that's broken things because if you don't make these conditions mutually exclusive every one of those questions is going to get asked and therefore answered and even if your grade is above a 90 it's also logically above an 80 above a 70 above a 60 and if i' kept it in there I would have failed as well with an F really good question other questions here on this form of logic like it would there be any I guess better way to kind of clean up even just this simple statement like we had before the previous one that you had with the El oh I I I like your enthusiasm for simplifying things further I'm going to go out on a limb here and say this is about as good as it gets at least using only conditional statements I can if my mind wanders think of a slightly more clever way to do this maybe with something called a loop or another programming construct we don't have that yet in our vocabulary but yes there's absolutely other ways to do it but I think not yet if we want to restrict ourselves to just words like if and or and else uh and L if and and and the like well let me propose that we pivot now to use another approach here that uses one other symbol that up until now we've not really had occasion to use let me propose that we Implement a program uh that we'll call parity in mathematics parity can refer to whether a number is even or odd and that's kind of an interesting question and turns out it can be useful in other applications too to I just ask the question is a given number even or odd maybe that the user typed in and let me go ahead and write a new program called parity Pi via code parody. Pi in my terminal and let me propose that we use this as an opportunity to introduce the last of those arithmetic symbols at least most of which we're familiar with addition subtraction multiplication division but there's been on this list before this last one here a percent sign and it doesn't mean percentage in this case when used as an operator in programming in Python rather it represents the so-called modulo operator for modular arithmetic or at least in our case we're going to use it to calculate the remainder when dividing one number by another well what do I mean by that well if you take a number like 1 divid 3 3 does not go into one eat cleanly so you have a remainder of one two divided three has a remainder of two three divided by 3 has a remainder of zero because it divides cleanly four divided 3 has a remainder of one because you can divide it in once but then that leaves one so it has a remainder of one and then lastly something like five divided by three has a remainder of course of two so that's all we mean by remainder how much is left over after dividing one number by another well if I go back now to my code and I consider how I might implement the question is this number even or odd let's consider how we might Implement that since it's perhaps not necessarily obvious how we can use this additional building block but it turns out it's going to be very useful longer term well let's first just get a number from the user in a variable called X and I'm going to set that equal to the conversion to int of whatever the user inputs after asking them what's X question mark and we've done that before many times how do I now determine if x is even or odd well it turns out if I have access to a programmatic operator that tells me the remainder I think I can do this in fact let me just ask the group and this is just from grade school math perhaps what does it mean for a number to be even to be clear a number like 0 2 4 6 8 10 12 12 14 16 those are all even numbers but what does that really mean Elena if I'm saying that right uh even numbers that can divide it exactly by two for example 2 4 6 8 and 10 and perfect and we could go on all day long literally since there's an infinite number of those even numbers but it's nice that you formulated it in terms of a question that we can ask very clearly is this number cleanly divided by two that is can we divide it by two with no remainder a remainder of zero well that's perfect because if we have this operator this percent sign that allows us to answer just that what is the remainder we can presumably check is the remainder is zero or is it one do we have nothing left over or do we have one left over well let's ask that if x ided by 2 has a remainder of zero as Elena proposes let's go ahead and print out something like quote unquote even and just say as much to the user else I think we can assume that if a number is not even it's going to be odd if it's indeed an integer so I'm going to go ahead and print out quote unquote odd instead and let's go ahead and now run python of parody. piy in my prompt what's X let's start with two two is in fact even let's start with four four is in fact even let's get thing let's get interesting with three three is now odd and I think we could do that all day long and hopefully get back indeed exactly that answer but what more could we do here how could we improve upon this well recall that we have the ability to invent our own functions and let me just propose for the sake of discussion that we're going to eventually find that it's useful to be able to determine if a number is even or odd and so we'd like to have that functionality built in and I don't think python has a function for telling me just that but I can invent it using Code like just this so let me go into my earlier version here and let me propose that we do this let me go ahead and write a main function I'm going to get back into that habit of defining a main function to represent the main part of my program and I'm going to do what I did before I'm going to get an integer from the user's input asking them what's X question mark and then I'm going to ask this question for the moment I'm going to naively assume that the function already exists but that's a useful problem solving technique even if I have no idea yet where I'm going with this how I'm going to invent a function that determines if a number is even I'm just going to assume that there's a function called is even and I'm going to call it blindly like this if is even passing in X then go ahead and print quote unquote even so if this magical function called is even returns true as its return value I'm going to print out that it's even else otherwise I'm going to assume that it's of course odd now the one problem with this program even if I call Main over here is that is even does not exist and this program would break if I ran it right now but that's okay I have the ability call to invent my own function so let me Define with def a function called is even I want this function to take an argument and I'm going to call it n just a number generically I could call it X but again I don't want to confuse myself as to which X is which so I'm going to give it a different name and that's fine I'm just going to call it more generically n for number and then I'm going to do this I'm going to say if n percent 2 equals equals z just like before then and here's the magic you the programmer can actually return what are called Boolean values we've seen in Python that python has stirs or strings ins or integers Floats or floating Point values all of which are different types of data in python python also has a fourth data type called bull for a Boolean value and even though this is just adding to our list the nice thing about bulls is that they can only be true or false an INT can be any number of infinite possible values a bull can only be true or false and it must be capital T and capital F if you're writing itself so if I go back now to my code and I consider exactly what I want to return here well if x if n% 2 equals equal Z that is if n / two has a remainder of zero well I think it's even to Elena your definition so let's return true capital T else if it doesn't have a remainder of zero I'm pretty sure mathematically it's got to have a remainder of one but it doesn't matter I know it's not even so I'm going to return false and we returned false instead capital F and now that we've defined both Main and is even and I'm calling main at the bottom I think I've got this right python of parody. Pi enter what's X let's try something simple like two and it's even let's do it again what's X how about four even once more what's X X how about three and it's odd now what have I done here I've just made the point that if I want to create my own function called is even that answers this question for me that I can now use in this program and heck maybe future programs that I write I now have a function that no one gave me I gave myself that I can use and reuse and I can even perhaps share it with others I'm using that function now on line three just to make a decision I'm using a conditional up there and my Boolean expression something that's true or false is going to be not something explicit like X less than y or y greater than x or the like it's going to be a function call I'm using a function as my Boolean expression but that's okay because I know because I wrote it that that function is even returns true or it returns false and that's all I need in a conditional to make a decision to print even or print odd so let me pause here to see if there's any questions now on how I've implemented is even using this bull hello hi David first of all thank you for this wonderful class uh did before yesterday and today uh I have just one query like bases on my background of java uh there when we used to pass the arguments we can also pass the address of the variables so is there any sort of this concept in Python uh short answer no those who are unfamiliar with Java or other languages or C or C++ there's generally ways to pass values in different mechanisms that allow you or disallow you to change them in Python no everything we're going to see is actually in fact an object but more on that down the line how about time for one more question here on these bulls and these is evens so I actually had a question about um defining a function okay if that's okay sure so if you define one are you like within your code like you made it up are you allowed to use the dot operator like we did name. strip and use it like that good question if you've created your own function can you use other functions like strip ortitle or Capital eyes that we've seen in the past um you can use those on strings those functions come with strings you can't necessarily use them on your own functions unless your function returns a string for the examples you gave I'm returning a bull bulls have no notion of white space to the left or the right you can't call strip you can't call capitalize but if you were writing a different function that that returns a string absolutely you could use those functions as well well let me turn our attention if I may back to this example here and consider as we now frequently do can we improve on the design of this code can I make this particular program better and I can there's a couple of ways here and I'll show you something that's now generally known as something pythonic there's actually this term of Art in the python world where something is pythonic if it's just the way you do things in Python which is to say we've seen already there's so many different ways to solve certain problems and in the python community of programmers there tend to be some ways that are smiled upon more than others and they tend to relate to features that maybe only python has but not other languages and here's some syntax that you might not have seen in languages like Java or C or C++ if you've programmed before and if you've never programmed before this too is going to be new instead of asking a question like this if else using four lines in Python you can actually collapse this into just just one more elegant line if you will instead of asking if n / 2 has a remainder of zero return true else return false let me delete all of that and just say this return true if n / two has a remainder of zero else return false now those of you who do have prior programming experience might actually think this is kind of cool you can condense from four lines into one on line that very same thought and one of the reasons why python is popular is that it does tend to read rather like English it's not quite as user friendly as most English or most human languages but notice now the line does rather say what you mean return true if n / two has a remainder of zero else false I mean that's pretty darn close to something you might say logically in English be it about even an odd or really anything else so that program is going to work exactly the same python of parity. Pi let me type in two it's still even let me type in three it's still odd but I can refine this even further and again consistent with this idea of not just writing correct code but writing better and better code but still keeping it readable I can do one even better than this notice this value here is my Boolean expression and it is going to evaluate to true or false is n / two having a remainder of zero or not like that is by definition a Boolean expression it has a yes no answer a true false answer well if your Boolean expression itself has a true or false answer why are you asking a question in the first place why ask if why say else just return the value of your own Boolean expression and perhaps the tightest version the most succinct and still readable version of this code would be to delete this whole line pythonic though it is and just return n modulo 2 equals equals 0 if it helps let me add parentheses temporarily because what's going to happen in parentheses will happen first n / by two either does or does not have a remainder of zero if it does the answer is true if it doesn't the answer is false so just return the question if you will you don't need to wrap it explicitly with an if and an else and in fact because of order of operations you don't even need the parentheses so now this is perhaps the most elegant way to implement this same idea now which is better this is pretty darn good and it's hard to take fault with this because it's so very succinct but it's perfectly okay and just as correct to have an if and then an else even though it might be four Total Lines if that helps you think about your code more clearly and it helps other people reason about it as well so it turns out there's another syntax that you can use to implement the same idea of a conditional whereby you do something optionally based on the answer to some Boolean expression and the keyword that you can now use in recent versions of python is called this match match is a mechanism that if you've programmed before is similar in spirit to something called switch in other languages for instance let me go ahead here and close out parody. py and let me go ahead and create a new file called house. py and in house dopy I think what we're going to do is try to implement a program that prompts the user for their name and then just outputs what house they're known to be in in the World of Harry Potter so for instance let me go ahead and do this let me give myself a variable called name set it equal to the return value of the input function and I'll say something like what's your name question mark and then after that I'm just going to use a traditional if L if else construct to decide what house this person is in so let me say if name equals equals say Harry as in Harry Potter well let's go ahead and print out Harry's house which is Gryffindor in the World of Harry Potter L if the name is instead Hermione then go ahead and print out also quote unquote Gryffindor as she's in the same house too L if name equals equals Ron let's go ahead and similarly print out Gryffindor quote unquote and let's make this a little more interesting now L if name equals quote unquote how about Draco Draco Malfoy in the books Let's go ahead and print out quote unquote Slytherin and just in case someone else's name gets inputed for now let's just suppose that we don't recognize them and say by default else print out quote unquote who question mark just to convey that we don't actually have a hard-coded response to that particular name let me go ahead now and run this as python of house. py enter and I'll go ahead and type in something like Harry and voila we see that Harry is indeed in Gryffindor let's run it one more time python of Housey let's type in Draco this time Slytherin and now let's type in an unrecognized name let's go ahead and rerun python of house. py and let's go ahead and type in Padma enter and who because we haven't actually hardcoded with an L if condition in this case uh what house Padma is meant to be in all right well it turns out there's other ways to implement this indeed there's some redundancy here in that we're checking if Harry or Hermione or Ron are all in Gryffindor I feel like we can at least tighten this code up a little bit using techniques we've seen already so let me go ahead and do this let me go up here and instead do something like this let's get rid of these two blocks of L ifs leaving just Harry's for a moment and let's use that or keyword again and say or name equals equals quote unquote Hermione or name equals quote unquote Ron thereby consolidating all three cases if you will into just one if statement then we still have a separate L if for Draco because he's not in fact in Gryffindor and then the final El to catch anyone else all right let me go ahead now and run this version of the program python of house.i I'll type in hermion this time she too is still in Gryffindor let me try it with Ron and that too still seems to be correct well it turns out there's another approach alog together that can perhaps make your code a little less verbose you could imagine how complicated this code might get if we had not just Harry and Hermione and Ron but a whole bunch of other names as well for Gryffindor for Slytherin and for all of the other Hogwart toes so you can imagine that code is getting pretty unwieldy pretty fast well it turns out another technique you can use is indeed this keyword called match which is very similar in spirit but the syntax is different and allows you to express the same ideas a little more compactly so let me go back to house dopy and let me propose that I get rid of my current if L if else approach and instead do this literally use the keyword match and type the name of the variable or value that we want to match on and then I'm going to go ahead and include a colon and then underneath that I'm going to include literally a keyword called case and the first case I want to consider is going to be Harry and I'm going to put Harry in quotes because it's a string or a stir and I'm going to have another colon at the end of this line and indented under that one I'm going to go ahead and for now print out Gryffindor which of course is Harry's house otherwise I'm going to have another case for quote unquote Hermione and similarly I'm going to have under that indented print quote unquote Gryffindor close quote now I'm going to have another case for Ron also in quotes with a colon now print quote unquote Gryffindor and now I'm going to have a other case for let's say Draco this one gets a little more interesting because Draco of course now is in Slytherin and then I'm going to go ahead and leave it as that for now so let me go ahead and save this file and go back down to my terminal window running python of house. py enter and let's go ahead and try Harry and he seems still to be in Gryffindor let's run it again for Hermione enter Gryffindor let's skip ahead to Draco and type in draco's name he's indeed in Slytherin now let's try another name that we haven't uh handled a case for like Padma again enter and we're just ignored there's no output whatsoever because there wasn't a case for Padma now we could of course go back in and explicitly add one for Padma but what if we similarly to the else construct just want kind of a catchall that handles anyone whose name is not explicitly specified Well turns out the Syntax for that using this new match statement is to still have another case but then to use this single underscore character which is used in other context in Python but for here it's meant to say whatever case has not yet been handled go ahead and print out as we did before for instance quote unquote who with a question mark at the end now let's go ahead and rerun this python of house.i I'll type padma's name again and this time I think we're at least going to get an explicit response indicating who whereas previously we did not have the equivalent of that now I think we've regressed a little bit we went from tightening things up by putting Harry and Hermione and Ron all in the same line and the same if statement but here we have now three case statements again for all three of those well we can tighten these this code up as well but the syntax is going to be a little bit different I'm going to go ahead and delete these two middle cases for hermion and Ron and then up here next to Harry's name before the colon I'm going to go ahead and use a single vertical bar and then a quote unquote hermy then another single bar and do quote unquote Ron and this is how using this relatively new match statement you can say the equivalent of Harry or Hermione or Ron but more concisely than you could using an if statement alone as we implemented it previously so now one final run of the program with python of house.i let's make sure that Harry is still in Gryffindor let's make sure that hermion is still in Gryffindor let's make sure that Ron is still in Gryffindor and indeed all three of them are now as always with python and programming more generally there's going to be different ways you can solve these problems this is just another tool in your toolkit arguably it has tighten things up arguably it's perhaps a little more readable because there's a little less syntax going on a little less duplication of equal signs and ell if and ell if and ell if all over the place but ultimately this would be an equally correct approach to that same problem but it turns out with the match statement you can do even more powerful forms of matching as well here we've used it simply to implement the same idea as that if L if else construct and it's worth noting if you've programmed in some other language the syntax here is indeed correct you do not need for instance a break statement as has been peppered throughout and you don't need something like default or something explicit you indeed just use this underscore as your catchall at the end of the match so just by adding in some of these new keywords here like if and L if and else we have now the ability to ask questions about values we have the ability to analyze input from users and ultimately make decisions about it and these then were our conditionals lying ahead is going to be the ability for us to not only use functions and variables and also these conditionals but also next Loops the ability to do something now again and [Music] [Music] again all right this is cs50's Introduction to programming with python my name is David men and this week we focus on Loops this ability in python and a lot of other programming languages to do something again and again a cycle of sorts and let's see if we can't begin by motivating exactly why we have this ability to do things cyclically using these Loops I'm going to go ahead here and open up VSS code and in my terminal window let's go ahead and create uh via code cat. py a Python program that meows like a cat and I'm going to go ahead here in this code tab very simply perhaps I'm going to start by implementing this cat just by using prints we're going to have this cat not make audible sounds but just print meow meow meow on the screen three times well I think the simplest way I can do this is just to print meow once and to print meow again and to print meow One Last Time on the screen and now let me go down to my terminal window let me run python of cat. py enter and meow meow meow all right so this program works this program indeed works if my goal is to get the cat to meow three times and let me propose just to help us wrap our minds around what's going on inside of the computer let me propose that we consider this flowchart so as before we have this flowchart that starts with a of this oval which just means start reading here and then notice it goes via arrows to a meow meow meow and then it stops it's perfectly correct and honestly it's wonderfully simple but I dare say we can find fault with my code nonetheless why is my code arguably poorly designed now the answer is going to be Loops in some way but let's see if we can identify in what way the code is actually poorly designed in some sense let's see any thoughts Alex okay so I mean repeating the same action like three times or even more um it's not a good habit yeah I'm just repeating myself and honestly it's not that big a deal if we go back to my code here am I really uh doing such a bad thing by just printing meow meow meow three times not really but let's consider The Logical extension of this suppose I want to meow four times or five times or 50 times or 500 times do you really think even if you've never programmed before is the solution to this problem really going to be to hit copy paste 50 times like probably not we can probably do better than that and Beyond it just being ugly at that point having so many lines of identical code just imagine if you wanted to change the code maybe I changed my mind and I don't want to make a cat I want to make a dog so now it has to say woof woof woof multiple times now I have to change that in like 50 different places and yeah sure I could do find and replace but come on like we're programmers now there's got to be a better way than just repeating ourselves so I bet we can do better than that if we think about a little harder what we how we go about structuring this program and we can do that if we augment our vocabulary just a little bit it turns out in Python and in other languages too there's a keyword called while and while is one way that we can express what's called a loop a block of code that's going to do something again and again and again zero times one time two times 50 times as many times as we want but while rather leaves to us the the particulars of how we express ourselves to do something again and again so let me go back over to vs code here and let me propose that I do this while is a construct that allows me to ask a question again and again and anytime we've seen a question it's been in the form of a Boolean expression a question to which the answer is true or false well how could I do this how could I print out meow three times and ask three times a question to which the answer is true or false well what if I did some counting right like literally on my fingers and if I'm trying to count maybe down from three I want to meow three times I can put three fingers up and I can meow and then I can put like one of the fingers down and then meow and I can put one of the fingers down and I can meow put one of the fingers down and maybe the question I can ask every time I meow is do I have any fingers up still do I have any fingers up still do I have any fingers up still and if the answer is true keep going if the answer is false stop so how can I translate that to code well once we've added this while keyword I think we have all the building blocks already let me propose that I do this let me propose that I give myself a variable and I'll call it I for integer but I could call it anything I want and I'm going to initialize it to three then I'm going to use this new feature of python while and I'm going to ask a question the answer to which must be true or false and I'm going to say while I does not equal zero so I'm going to ask the question while I does not equal zero do the following notice the colon at the end of the line notice my indentation and just like with functions just like with conditionals you indent the lines that you only want to execute as part of this other thing what do I want to do while I does not equal zero well I think I just want to meow but it's not enough just to write this code if I were to very dangerously run python of cat dopy and hit enter right now what might happen on the screen whether you've programmed before or not why is this a very bad thing potentially it's not going to break things but it might it might lose control of my computer somehow any thoughts uh yeah teimo hi uh I think it's going to continue uh to print out Mel since I is always equal to three and the W is always true yeah exactly if I'm initializing I to three that is setting it equal to three on line one then I'm asking the question while I does not equal zero and that's going to be true it does not equal zero it obviously equals three print meow and the way a while loop works is that the python interpreter just keeps going back and forth it goes from line one to line two then to line three and then it goes back to line two to ask the question again if the answer still true it goes to line three it then goes back to line two if the answer is still true it goes back to line three and to U's point if you're never actually changing the value of I it's always three you're just going to be looping literally forever and this is an accidental infinite Loop so we've got to be smarter than that and I'm not going to hit enter because I don't want to lose control over my computer here such that it's printing out meow forever um fortunately if you ever do do that and you find yourself in an accidental infinite Loop control C for cancel or interrupt is going to be your friend if you ever seem to lose control you don't need to like reboot or turn off the computer you can just hit contr C in your terminal window and that will likely fix it all right well what do I want to do then after meowing each time I think what I'd like to do here is maybe something like this let me update I to equal whatever the current value is uh uh minus one here whoops sorry minus one so if I on each iteration am updating I to be one less one less one less it should eventually hit zero at which point the answer to 9 2's question will now be false so let's see if this works I'm going to go down to my terminal window and run python of caty and I indeed get three meows why because I've kind of wired this up kind of like a machine in software if you will I've set I equal to three then I keep asking this question but I keep turning the gears I keep changing the value of the variable to make sure that ultimately it is actually being decremented that is decreased by one until we eventually hit zero now for those of you who think a little more graphically let me pull up one of our usual flowcharts this is just a representation graphically of the exact same thing notice what's happening I first start the program and then I initialize I to three and then I ask the first of my questions again the diamonds always represent questions and the answer is going to be true or false does I not equal zero well it doesn't it equals three so if I follow the true line I meow and then I follow this arrow and I update I to equal IUS one at this point in the story I presumably equals two mathematically I Follow the arrow and there's the loop this is why it's nice to see this graphically perhaps because you can literally see the loop back and forth now I ask the question again does two not equal zero well it does not equal zero it's two so we meow again we change I from 2 to 1 well does one not equal zero well obviously it is not zero so we meow again we decrement I again I is now zero does 0 not equal zero no it equals zero so the answer is false and we stop so there perhaps more so than any of our flowcharts before do you really see the structure of what's Happening inside of the program and you don't have to get into the habit of making these charts or creating these charts but just as a first pass at what's going on inside of the computer that's indeed one way to visualize it instead well let me propose that like always there's many different ways to solve this problem and suppose you just like to think a little differently maybe you don't like starting at three and then counting down to zero y maybe your just brain doesn't work that way and you prefer to count up instead of down totally fine let me go ahead and change my code here to set I equal to 1 instead of three and here let me just change my logic rather than checking for not equal to zero like maybe you don't like thinking terms of not because it's a little confusing and it might be let's just check that I is less than or equal to three so we'll be a little more explicit we'll count from one up through three each time printing meow but I'm going to need to change this line here let me see if we can't call on someone to change line four for me how do I want to change line four to be consistent with counting from one up to and through three I would be plus one every time you meow yeah exactly in this case we want to add one not subtract one and in fact if you think about this this two could end very poorly right if you start counting at one and you keep subtracting one subtracting one subtracting one I think we're going to find oursel with the same problem which is that we're never going to stop because we're going to keep getting more and more negative as opposed to ever getting up to the number three so I think you're right I need to change this to be IAL I + 1 and now notice just for Clarity 2 the equal sign is again our assignment operator from right to left logically this might otherwise strike you as strange like how can I equal itself plus one well it doesn't until you execute this code from right to left you add one to I or You Subtract one from I and then you update the value of I on the left the assignment copies the value from the right to the left well how else might I do this well I will say that most programmers computer scientists more generally tend to start counting from zero it's a convention and it actually has upsides even in Python and other languages where generally speaking it's a good thing to start counting from zero instead of counting like we might in the real world from one let's go ahead and adopt that convention now let me set I equal to zero and I need to make a change now notice if I don't change my logic this program just became buggy the cat has a bug it's now meowing four times if I run it as is but the easiest fix here would be to change my inequality to be this less than instead of less than or equal to now I'm starting at zero but I'm going up two but not through three and even though this might of all the things we've seen thus far seem maybe the least familiar most of us might start at one two then three it's a good habit to get into now start at zero and go up two but not through the value that you care about ultimately three in this case here well let me tighten things up a bit here not only will this now fix my counting problem it now meows three times as expected there's a more succinct way to express I equals I + 1 and this is because it's such a popular thing to do in code you can instead just say i+ equals 1 and that's it you don't need to put everything on the right hand side this is a special syntax that says the exact same thing increment I but it does it with a few fewer keystrokes it's just a little more pleasant to type it's a little faster to read it's it's just a convention those of you who have programmed in C C++ pyth uh not python C C++ Java Java Script might have seen plus plus before or minus minus sorry python doesn't have it so you cannot use that this is a succinct as your line of code might get all right let me pause here to see then if there's any questions about these implementations of while Loops um can we use stuff like four Loops which um have a certain I value initialized to it at at the start and it runs from the particular condition you put into the um into the thing and increment it as as you go along short answer no you cannot do what you're describing but there is another type of for Loop that we will soon see but let's come to that in just a moment other questions on Loops using while here so I had a question about the flowcharts okay uh there were c yeah there were certain symbols for the certain kind of the statements uh sir they are they certainly used for that kind of statement that they are put they are so I deliber use anyone I deliberately use certain types of symbols certain shapes here uh whereby in oval is conventional for start and stop I used rectangles for any statement of code like an assignment or a printing and so forth and I use diamonds to represent uh questions that you might ask uh conditions as we've seen um if you're doing this for yourself if you're just trying to make sense of your code and writing it down you certainly don't need to use these formal symbols but I tried to be consistent with some PR best practices and in fact let me come back to the same picture because this was the first version of our picture but we've since modified our code a couple of times this recall was the version where the question we were asking was I not equal to zero let me go ahead and just change this code now to represent the next version we did which recall changed our logic to start counting from one it changed our question to check is I less than or equal to three but then everything else was the same except for the counting which is now Plus instead of minus and then we refined it a little bit further by counting now from zero up two but not through three and we tightened up this code here by just incrementing one by using the slightly more succinct syntax so at this point these flowcharts might become less and less useful for us because once you've wrapped your mind around the concept and hopefully the picture helps bring that concept to life it's certainly fine to focus entirely on the code and only think about or even draw something like this if you need to wrap your mind around something more complicated than you're used to well let me go ahead if I may and propose that we transition to another approach of types of Loops using another keyword here namely a for Loop and this is a word that does exist in other languages but doesn't necessarily have as many features as other languages might use it for but there is a different type of loop not a while loop but a for Loop and a for Loop is going to allow our allow us to express ourselves a little differently but to do so I'd propose that the easiest way is if we introduce one other ID in Python which is that of a list and here too no pun intended we're adding to the list of data types that python supports we've seen stirs or strings ins or integers Floats or floating point value use bulls or Boolean Expressions python also has lists which is another type of data but wonderfully this one's probably pretty familiar a list of things in the real world is a list of things in Python it's a way of containing multiple values all in the same place all in the same variable so what do I mean by this well let me propose that we go back to our VSS code here and let me kind of start fresh with my code here and not use a while loop at all but let me use this new keyword for the way the for Loop works is that it allows you to iterate over a list of items so what does this look like it might look like this for I in the following list of items 0 1 2 this is my starting point and on each iteration of this Loop that is on each execution of this loop again and again I want to print out meow now I'll admit I kind of like the look of this code already even though there's some new syntax here because it's just short order than the while loop right the while loop had multiple lines a moment ago and it was entirely up to me to decide what i is I have to check a condition I have to increment or decrement I like I was doing a lot of work relatively speaking to make that thing turn to make that Loop go and go it was very mechanical in a sense you can kind of in your mind's eye maybe see the gears turning as all of these variables are uh changing and these questions are being asked a for Loop kind of simplifies all of that and it just says if you want a variable like I a number and you know in advance how many times you want this Loop to execute three times we'll just kind of specify what it is you want I to take on as values explicitly in this loop I will be automatically initialized by python to be zero then meow will be printed then python will automatically update I to equal 1 then meow will be printed then python will automatically update I to B2 and meow will be printed and because that's it for the values in that list python will stop and it will only me meow a total of three times what is the list the list in this program is exactly that 0 comma 1 comma 2 and notice the square brackets those aren't parentheses those are square brackets that represent a list that's how you know visually as the programmer that's how python knows as the language that you intend for that to be a list so let me go ahead and run this python of cat. piy and it works just the same but it's only two lines it's pretty readable once you have familiarity with that construct but to my constant point about correctness not necessarily being the same as design in what sense is this program perhaps poorly designed It's seems to work it meows three times but why might this not be the best way to solve this problem even if you've never programmed before again think about Corner cases things that may or may not happen think about extreme cases that really test the quality of this code okay I think that because like we can we are saying 0 one two which is three times and then like if you want to print a million you say one two three yeah exactly and that's what I mean about thinking about the extreme cases if you're trying to decide for yourself if your own code is good or someone else's code is good it might look so at first glance but think about the extreme well what if it's not three things it's a million things I mean are you really going to write out one Z through a million or 0 through 9 uh you know 999,000 uh 999,999 like no you're not going to write that many numbers on the screen there's got to be a better way so let's do the better way from the get-go rather than set the stage for doing something poorly and the one way we can solve this problem to improve the design is don't just manually specify ify the list of values use a function someone else's function that comes with python that gives you the list you want and the easiest way to do that in Python is to use a function called range that returns to a range of values it expects as input at least one argument and that number is going to be the number of values you want back those values are going to start at zero and go to one to two and so forth but they will go up to but not through the number you specify so by specifying range three you're essentially being handed back one two three values and by default those values are zero one and two and that's it but what's brilliant about this is that now to Hope's point if I do want to meow a million times I mean that is an angry cat I can now do a million by just typing a million I don't have to literally type zero comma one comma 2 comma 3 comma four all the way up to 999,999 I just do this so that's to be a better way long term so that's indeed one Improvement we can indeed make here still using a for Loop but now using this range function and just to show you something else that's pythonic this is not strictly necessary but it's commonly done there's a minor Improvement we can make here even if we're just meowing three times and notice that even though I'm defining a variable I I'm not ever using it and it's kind of necessary logically because python Pres presumably has to use something for counting right it has to know what it's iterating over but there's this convention in Python where if you need a variable just because the programming feature requires it to do some kind of counting or automatic updating but you the human don't care about its value a pythonic Improvement here would be to name that variable a single underscore just because it's not required it doesn't change the correctness of the program but it signals to yourself later it signals to colleagues or teachers are looking at your code too that yes it's a variable but you don't care about its name because you're not using it later it's just necessary in order to use this feature this Loop in this case here so just a minor uh Improvement or change there but to really get you intrigued by what's possible in Python let's take this one step further so if we really want to be pythonic this one if you've programmed before is kind of going to blow your mind so to speak whereby if I want the cat to meow three times what if I actually do this print open parenthesis quote unquote meow times three all right you have to be kind of a geek to think this is cool but this is kind of cool so you can literally just print what you want multiply it by the number of times that you want it and you will get back exactly that result now I've kind of made a mistake here so let's see what this does it's not quite as beautiful as this code might look to to to you to some of you to me let me run python of cat dopy enter okay it's a really like Hungry Cat or something it's meowing really fast but I can fix this I bet let's think about now some of the basic building blocks we've discussed the problem is clearly that literally meow meow meow is being repeated three times but it's not as pretty as I want it I want it to be meow meow meow on separate lines what might be a possible solution here while still using this multiplication operator and think back we've used plus to concatenate strings you can apparently use multiplication to concatenate strings but more than once again and again and again how could I clean this up without reverting to my for Loop or my while loop and still use multiplication in this way uh we can use a escape sequence which should did back slash n amazing yes think back to back sln which is the way you as the programmer can express a new line in code and I think if I take your advice I put a back slash n there inside of my quotes So that at the end of every Meo W there's a new line let's see how this looks Let Me Clear My screen and run python of caty okay so close I like this let me call on someone else the only thing I don't like and I know I'm being really nitpicky now is that it's meow meow meow on separate lines but there's kind of this extra blank line which I'm just not loving aesthetically I think we can uh make end equal to column uh column not back n yeah so here too like all of these things we've seen in past weeks are kind of coming together right recall that the print function lets you control what the line ending is by default it's back slash n itself which is why at the very end of this print the cursor is being moved again to the next line well we need to just override that so let me go into my code here and let me change this to comma n equals quote unquote so that it's no longer the default back sln it's instead now going to be uh nothing whatsoever that should eliminate then hopefully that additional uh blank line so let me run this one last time here python of caty enter and there we have it so now you know at least as programming goes it's kind of cool that I can distill this into a short line and express myself all at once now to be fair it's a little less readable like now I've got back sln I've got time three I've got n equals quote unquote so you don't have to do things this way my previous approach with a for Loop totally fine my previous approach with a while loop totally fine and in some sense perfectly welld designed but this is just yet another way to do it but it's not a good thing if you or your teacher your colleague your friend are going to struggle to read your own code but this is a feature of python that some languages do not in fact have all right well let me propose that things get more interesting still if we're not just swing three times only but we're meowing some variable number of times let's ask the user how many times this cat should meow so let me clear the screen here and let me figure out well how do I get a number from the user the catch here is that if I want the user to give me a number I'm not doing math per se I'm meowing and therefore the user has to give me a positive value the user has to give me a positive value so how can I insist on this well if I just do this n equals int of input uh what's n question mark well I want to check like I could say if n is less than Z like if it's negative well I could do this well then ask again int input what's n question mark okay well what if the user still doesn't give me a positive number what if they're being really difficult they're not paying attention and they typed in two negative numbers well if n is less than zero well let's do it again n equals right this does not end well you can't infinitely many times keep checking is it negative is it negative is it negative right the program would never be done written so we can do this I think better maybe with a loop so let me propose this a very common Paradigm in Python when you want to get user input that matches a certain expectation you have that it's all positive that it's all negative or just something like that you just immediately say while true you deliberately and a little dangerously but a very conv intentionally induce an infinite Loop now what is an infinite loop it's just one that goes forever and we've seen how that can happen accidentally mathematically it's absolutely going to happen when you say while true why well the answer to the true question is always true so this is a way of deliberately inducing a loop that by default is going to go forever so we're going to need a way of breaking out of this Loop when we have the number we want the convention though inside of this otherwise infinite Loop is to ask the question you care about like give me an in by prompting the user for input like what's n question mark and then just ask your question so if n is less than zero then I think we want python to just continue to prompt the user again that is we want the code to stay in the loop recall the input function and hope that the user gives us a better answer if this time around it's less than zero so let's just literally use Python's keyword continue which says just that continue to stay within this Loop else if it's not less than zero let's go ahead and just break out of the loop altogether using another keyword in Python break break will break you out of the most recently begun Loop in this case if it's not the case that n is less than zero so this will work and it will allow us to get a value that's zero or greater from the user but I think we can tighten it up further so it's to not bother having an if and an else why don't we instead just say if n is greater than zero go ahead and break in fact it's not that interesting a program if we even allow the user to type in zero so let's wait and until they give us an integer that is greater than zero and then break out of this Loop and what can I now do down here for I in range of whatever that value n is print meow and honestly I don't need I here so let me come back to that principle before and let me just change it to an underscore just to be pythonic if you will so what's going on lines 1 through four deliberately Implement an infinite Loop that otherwise by default is going to go forever but I'm asking a question inside of that loop after getting an INT from the user on line two I'm then checking is it greater than zero or is it zero is it negative none of which makes sense for a meowing cat like I want the cat to meow at least one time so if it is greater than zero break and this break statement even though it's indented indented twice has the effect of breaking out of the most recently begun while loop so once the user gives you a positive value then we get to line six at which point we meow that many times because of line six and seven so if I run this now python of cat. Pi enter well what's n let's start with three where we begin meow meow meow well this time let me go ahead and increase the size of my terminal window just temporarily let me run python of cat. let me do it 10 times meow 10 times now appears on the screen and the takeaways here are not just that we can meow 10 times or do something again and again but this is a very common Paradigm in Python when you want to do something again and again and again but only until the user actually gives you a value that you care about here and let me propose actually now that we practice a little more what we've been preaching especially when it comes to say especially when it comes to say writing your own functions you know now that I'm doing all this meowing it might be nice to actually have a meow function that the inventors of python didn't Envision so let me do this let me actually get rid of this code and let me go ahead and do this let me go ahead and say Define a main function as I've done before and let me just blindly call meow 3 meow doesn't exist yet but when it does that'll be great so let me go ahead now and Define meow so my meow function should take as input a parameter called n or anything I want and this part's pretty easy now how do you meow in times well for underscore in the range of n Go ahead and just print meow so same code AS before nothing new here I'm just putting that logic inside of a meow function that's going to have this side effect of printing meow and now as before let me go down here and let me make sure I call Main and if I now run this code python of cat. meow meow meow it's always going to do three because I've hardcoded the three well let's make one Improvement here let me go ahead now and maybe do this uh let me ask the user for a number so let's say something like this number equals get number all right unfortunately there is no function in Python called get number that gets a positive number from the user but I can invent that so Define get number open paren close per n and then inside of this function let me do this while true go ahead and get a number from the user converting it to an INT asking them what's n question mark and then if n is what I want it's a greater than zero value a positive number I don't want to break this time necessarily although I could I instead want to return the value so I can actually do this instead and this two is a feature of python this ability not to just break out of a block of code but also to return a value in code to actually return a value gives you the ability ultimately to return explicitly a value so that your function has not just a side effect necessarily but it actually hands back just like input does just like int does just like float does an actual value to the user now to be clear I don't have to return n here I can still break out of the loop as I've done in the past with code like this but then after the loop I still have to return n and so what's happening here is that if you use break to get out of the loop but you need to hand back a value from a function you still have to use the return keyword now explicitly either in the loop as I did or now outside of the loop but still inside of the function the last thing I'm going to do here now is change that three which we hardcoded earlier to actually be the value of the variable we've gotten from the user so that now down here if I run python of cat. py enter what's N I can type in three I get my three meows or if I only want one I now get one meow instead all right so if we now have this ability to do things again and again in these Loops let's see if we can't solve some other problems via which to express ourselves cyclically but get back some interesting answers as well let me propose for instance that we look a little more closely at these lists it turns out that in Python and really in programs in general it's useful to have a list of values because we're going to be able to work with more and more data larger and larger data sets so let me propose that we come back to vs code here and let's do something that's perhaps a little familiar to some folks um the world of Hogwarts and let me go ahead and code up a file called Hogwarts and let's see if we can't have a list of students at Hogwarts here so I have a new tab called hogw Works sty and let me go ahead and propose that I just Define in this program a list of students whose names I know in advance so I'm not going to get user input for now I'm just going to know from the GetGo that the three students I want to consider are these a variable is going to be called students it's going to equal as I've done in the past a square bracket which means hey here comes a list and those values are going to be Hermione in quotes because it's a string uh Harry in quotes cuz it's a string and then WR in quotes because it's a string as well so this is a list of length three it's similar in spirit to my list of length three earlier but that had three ins 012 now I have a list of three strings instead and this isn't very useful at the moment but let me just do something as a check for myself let me print out each of these students well wait a minute how do I print the contents of a list well in the past when we've printed a variable we've just printed out the name of the variable but I don't want to print out all of Hermione and Harry and Ron all at once maybe I want to print out Hermione first then Harry then Ron so I need a way to express more precisely which value do I want from this list and the way you do this in Python is you use square brackets in another way if you have a variable in this case called students and you want to go inside of that variable and get a specific value that is to say you want to index into the list you use square brackets this way using numbers inside of the square brackets and here's where we see that it is useful to think and count in terms of zero on up instead of one on up these lists in Python are shall we say zero indexed the first item in a list is at location zero the second item in a python list is at location one and the third is at location two so you're always kind of off by one mentally but you get used to it if you've never programmed before over time so let me print out all three students so let me print out students bracket zero then students bracket one then lastly let me print students bracket 2 and this is my third and final line and of course if I run this code it probably does what you would guess if I run python of Hogwarts stpy there's Hermione Harry and Rob each on their own lines there but there's got to be a better way right especially if I don't know in advance who's going to be in this list if next year there's some new students at Hogwarts we can use a loop to do something automatically without having to manually type out zero and then one and two well here's another feature of python you can use a for Loop not just to count from zero to 1 to two you can use Python to just iterate over anything not just numbers but strings so I could actually do this for student in students colon and then indented underneath that I can say print student now it doesn't matter if I have three students or four or 400 this two lines of code this Loop will print all of those students for me one at a time so if I now run python of Hogwarts there's the same list but I don't need to know in advance how long that actual list is now notice I made a conscious decision here I didn't call this variable underscore because this time I'm using the variable and while I could do this now no no no no your code is getting way too cryptic if you're naming the variable underscore and you're using the variable underscore now you're helping no one now you're confusing the reader yourself in the down the line you should call your variables what they are so an very appropriate name though I'm sure you could come up with others would be student and here you could say you would say student as well if you'd prefer to be more succinct it's not unreasonable to do something succinct in a loop like this for s in students using maybe the same letter that the list itself begins with but again why bother python is meant to be more readable if you have a list of students iterate over them one student at a time let me pause here to see if there's now questions about lists as I've now defined them a list of strings in this case or using a for Loop now to iterate over and print each of those names yeah uh so is it not necessary to initiate student in this case or we can just declare a variable in the loop good question you do not need to manually initialize it python takes care of initializing the student variable to Hermione first then Harry second then Ron third unlike other languages you don't need to initialize it to something yourself it just exists and it will work other questions on loops and lists in this way since you describe break so is there any concept of continue so that we can skip a particular case in Loops yes you can continue using another syntax as well we haven't shown that for now we focused only on break H okay sure uh can can this follow work with either hash tables or different kind of fight tables or arrays uh indeed so we're getting ahead of ourselves there but there are yet other types of data in Python and indeed you can use a for Loop to iterate over those as well anything that is iterable so to speak is a piece of data that can be used with a loop like this but more on those more on those soon in fact let me transition here to show just another way of solving the same problem because up until now when we've used Loops we really have relied on numbers and that's fine if you prefer to sort of stay in that space suppose I did want to iterate using numbers like I and 0 1 2 and so forth let me propose that we could change this code AS follows if you would prefer to think about or if the program you're trying to implement requires that you use numbers like this you might do this for I in well I don't want to just say students because then I is not going to be a number I is going to be literally Hermione then Harry then Rob I need to iterate from zero to one to two right if I know a list with three elements has these locations 0 1 2 I need to create a loop somehow that starts at zero and ends at two previously when I wanted to do that I needed range but this two is not going to work I can't just say in the range of students because students is not a number it's not an integer so you can't pass it to range range expects an integer but there is a solution here it turns out that there is a function in Python called length or Len Len that will tell you the length of a list and other things down the line too and now I think I can assemble these building blocks in a way that can allow me to use numbers in this way so range doesn't take a list of strings it takes a number and ideally that number is going to be three so I get a range of values 0o 1 and two so I think I can Nest my functions like this if I first get the length of the student list that's going to be three then I pass that return value as the argument to range that's going to give me back a range of value zero then one than two and what that's going to allow me to do then in code if I want is not just this I could do print now students bracket I and this is now where the syntax we're seeing is getting very expressive new and perhaps unfamiliar but if I can do Open Bracket zero close bracket or Open Bracket one close bracket or Open Bracket 2 close bracket turns out I can actually put a variable in there and I can express any number inside of those brackets so it's to print these all out dynamically in a loop let me do this python of Hogwarts enter there's Hermione Harry and Ron and now if I'm just curious I I just want to poke around or maybe I want to do a ranking like who are the top three students in the school or in Gryffindor well I can print multiple things at a time we've seen let me print out not just the students at location I but rather let's print I first and then the student at location I so two things to print and we know that print can take two arguments we've seen that before they'll be separated by a space let me go ahead and rerun this now I see that okay hermion is the top student but she's in zero place that's a little weird like we don't need to show the human using my program that we started counting at zero I can clean this up I can just add one to the eye up here and now we see sort of a top three list of students hermion is number one Harry's number two and of course Ron is number three so we can get access to all of those same values as well all any questions now on on these lists any questions now on these lists this length these ranges or otherwise my question is uh for I in range can you explain this once more uh sure still so let me rewind in time we started off doing this for I in 012 and then we print it out meow three times in that way the way that the for Loop works is that it creates for you a variable that I've called I but I could call it anything I want it then assigns I initially to the first thing in the list it then automatically assigns I to the next thing in the list and then it assigns I to the third thing in the list and each time it does all of the indented code underneath we realize though that this is not going to scale well if I want to do something like a million times so we introduced range instead that has the effect of doing the same thing it returns to me a Range of values a list of three things really so the behavior is exactly the same if we now fast forward to this Hogwarts example now though what I'm doing is just combining these smaller ideas I'm still creating a for Loop I'm still creating a variable called I I want to do it over a range of values but how many values well if I use the length function and pass to the length function the list of values lengths purpose in life is to tell me how long is this list and it's three so that's almost as though before I had just done something like this but I don't want to hard code three I want to dynamically figure out how many students are at Hogwarts so I'm just composing composing composing or nesting all of these various ideas all right if I may let me transition now to hog in Hogwarts still to introduce one final type of data before we combine everything with a few final programs it turns out in Python there's not just strings not just ins not just floating Point values not just bulls not just list there are also what are called dictionaries or dicts which are a data structure that allows you to associate one value with another literally a dictionary like in the human world if you were to open an a dictionary be it in English or any other human language what's inside of a dictionary well it's a bunch of words and definitions a computer scientist though and a programmer would describe those more generically as keys and values something associated with something else that's all a dictionary is it allows you to associate something with something else and notice this is already more powerful more interesting than a list a list is just a set of multiple values but a dictionary is sort of two-dimensional if you will just like a human dictionary a book it Associates something with something else like words with their definitions now what does this actually mean in practice well suppose that we wanted to keep track of who is in what house at Hogwarts well I could do it using lists alone let me go back to vs code here and let me just temporarily but in a way that I'm not going to like ultimately let me create another variable called houses set it equal to uh Gryffindor corresponding to herm's house uh Gryffindor corresponding to Harry's house and Gryffindor corresponding to Ron's house and let's add Draco in there so we now have four instead of three students just so we have a little variety and he was in uh Slytherin so now we have two lists and we could just agree amongst ourselves that whoever is first in the students variable lives in the first uh value in houses whoever is second in students lives in the second house whoever third in students lives in the third house we could do that but honestly that is going to break down quickly when we have a lot of students when we have a lot of houses and what if we want to keep track of more things than that what if we want to keep track of every student's house and the Patronis this uh this image that they conjure up magically well then we need a third list like this is just going to get messy quickly if we're just on the honor System using multiple lists where everything lines up logically it doesn't end up well when your code gets more complicated but I do want to implement this idea I want to associate something with something a student with a house a student with a house a student with a house and so forth so how can I go about doing this well let me go back to my code here and let me propose that we do this using a python dictionary and this is the last of the new syntax really that we'll see here's the new syntax instead of using square brackets we're going to use curly braces for dictionaries as well we've seen curly braces in the context of f strings completely unrelated sometimes you run out of keys on the keyboard and the authors of a language need to start reusing symbols in different ways that's what's about to happen we're using curly braces in a different way now so let me create a variable called students and let me go ahead and set it equal to open curly brace and Clos curly brace this is an empty dictionary at the moment and here's how a dictionary works it allows you to associate something with something else and you do that like this Hermione quote unquote colon and then the value thereof what do you want to associate with Hermione well Gryffindor what do I want to associate Harry with well I want to associate him with Gryffindor what do I want to associate Ron with well I want to associate him with Gryffindor well this is actually not going to this is going to get very ugly quickly once we add in Draco and Slytherin my code is going to get too long it's going to start wrapping so this is purely aesthetic it is perfectly acceptable in Python and other languages to format your code a little more readily and just add new lines if it makes it more readable and one way of doing this might be as follows I still have my curly brace up here I still have my curly brace down here but notice it's a little more readable now in that I have my keys on the left my something and my values on the right my other something it's just a little easier to skim top to bottom you could format it differently as well but I'm going to go ahead and add in now uh Draco who lives of course in in Slytherin so now I have each of these keys on the left and values on the right which is really again just a code implementation of this idea a little chart that you might write up with paper pencil when associating something with something else so how do I now use this code in an interesting way the syntax is almost the same if I want to print out the very first student herm's house I could do this print out the name of the variable but I need to go inside of the variable I need to index into it and what's neat about dictionaries is that whereas lists have locations that are numeric zero 1 2 Hermione Harry Ron respectively dictionaries allow you to use actual words as your indices so to speak your indexes to get inside of them them so if you want to print out herm's house the key you care about is quote unquote Hermione and what this syntax here will do notice it's not a number zero or one or two it's literally herm's name this is like going to the Chart earlier and saying all right give me uh Hermione is my key Gryffindor is the value that's what we're doing here syntactically we're looking up hermion and getting the value thereof so if I go back to my code that should print out Gryffindor and if I do this a few times students bracket quote unquote Harry should give me Harry's house print students Open Bracket Ron that should give me Ron's house and then lastly if I do this with students bracket Draco that should give me draco's house now it's a little manual still I'm bet we can improve this but let me run python on Hogwarts sty and we should see Gryffindor Gryffindor Gryffindor Slytherin which is exactly what we'd expect now all we've done again is we've just now moved from having just a simple list of names to again sort of two Di ions associating like we would on paper pencil something with something else keys with values respectively allow me if you will even though I realize this is getting a little fancy allow me to escalate things slightly here and transition from looking at just for instance uh that pattern there just hardcoding those values there to actually printing these out more dynamically let me go ahead and use our Loop and this question came up earlier as well let me go ahead and say for each student in students go ahead and print out for instance the students variable at well let's just say student first let's keep it simple so this is not going to be that interesting yet but when I run python of Hogwarts upy and hit enter notice what should I see let me take a question here to see what am I going to see when I hit enter now when I'm doing for student in students yeah I think we we we will only see Keys perfect so good intuition it could have gone both ways could have been values the houses but when you use a for Loop in Python to iterate over a dictionary by design it iterates over all of the keys so we should see I think Hermione Harry Ron and Draco let me hit enter now enter and indeed you're exactly right we see just the keys but that's not really that useful if what I really care about is who lives where can I print out both well I think I can let me go ahead and do this let me print out not just the students name the key but let me use the key their name to index into the dictionary right if I know the word in the dictionary let me look up its definition if I know the student's name let me look up their house and the Syntax for this just like a list is students bracket and just like in the past we used I when I was a number we can also with a dictionary use a string so if the student's name is the key then this syntax students Open Bracket student close bracket will go to hermion location and get back her house we'll go to Harry's location and get back his house and so forth so if I do python of Hogwarts enter now I see Hermione Gryffindor Harry Gryffindor Ron Gryffindor Draco Slytherin now it looks like I've given them all new last names but I can clean that up this is just a print thing let's go ahead and change our separator from the default space to maybe a space comma and just using print features now let me run the same program again enter now I've just got some nice pretty commas in there to make clear that herm's last name is not in fact Gryffindor but that's just a print detail any questions then on these dictionaries and what I've just done questions on these dictionaries and this looping over them here um I just can't get my head around the uh for student in students does uh if I'm just correct me if if I'm right does that mean it Imports the list of students and uses the indexes in other words herione Harry and Ron as the indexes in the actual um the list of students correct so this is just a feature of python when you use a for loop with a dictionary what happens is this if this is the dictionary here with the keys on top and the values on bottom you get to choose what the variable called I called my variable student just because it makes sense because I want one student at a time and what the for Loop does just like it did with numbers before the zero the one and the two it allows me to for instance set student equal initially to herm's name and then the next iteration of the loop the next cycle sets student equal to Harry's name then Ron then Draco it just kind of happens automatically like that is what the python interpreter does for you when it sees a for Loop like that so it's very similar in spirit to iterating with a for Loop Loop over a list but rather than iterate over the numeric location 012 it iterates over the boldfaced keys in this representation here graphically and allow me to give us one other example on Hogwarts before we look at one other familiar uh domain at the risk of things escalating a little bit let me propose that we continue the story with one final Hogwarts example like this what if we have more information about each of our students and this is kind kind of inevitable right if you're implementing a program that's a database with people or customers or employees or anything else you can imagine having a lot of data about anything you're representing in your program here for the sake of discussion suppose that every student at Hogwarts of course has a name they have already a house but they also have a Patronus for those unfamiliar this is the animal or entity that comes out of the end of their wand when they make a Certain Magical spell the point here being is that we want to associate not just one one thing with the student but multiple things as well their name their house and their petronus in this case well what might code like this look like well let me go back to Hogwarts toy and let me start fresh for just a moment and let me propose that I enhance this with a bit more data and this data is going to look as follows my students variable now I'm going to propose we think of it as a list what if we have a list of dictionaries as follows indeed I want to literally implement this picture here so notice that my previous picture just represented a single dictionary but suppose I wanted to compose a list of dictionaries that is four students so a list of four students and suppose that each of those students is itself a dictionary a collection of key value pairs keys and values something and something else well here's one other way we can do this in code let me go back to s code here and let me Define a variable called students that is equal to a list and I'm going to preemptively move my cursor onto separate lines because I know this is going to be long and I want to fit all of the elements of this list inside of it I'm now going to create a dictionary one dictionary per student and how do I create a dictionary I just use those curly braces but it's up to me to Define what those keys are and let me propose that one key this time won't be the student's name explicitly it will literally be the word name and they're going to have the name Hermione this same student is going to have another key called house and the value is going to be Gryffindor and the same student's going to have a third key called petronis and the value of that is going to be I had to look it up in otter according to the book now I'm going to create a second dictionary inside of this list and again a dictionary is like literally like the human dictionary of words it's a book that contains keys and values words and definitions what are the three words I'm storing in each of my dictionaries name house and petronis what are the definitions of those words for Hermione Hermione griffindor and Otter respectively for Harry the definitions are going to be different in this new dictionary let me give myself another pair of curly braces and say this name quote unquote colon Harry uh house here is again going to be Gryffindor and this one I I knew his Patronis is going to be in this case a stag all right next a third dictionary the name here will be Ron and I'm going to go ahead and do that just like this next I have the house and he too was Gryffindor lastly had to look this one up Ron's petronis was a Jack Russell Terrier lastly is Draco in a third in a fourth dictionary now so another pair of curly braces the name of the student is of course Draco the house of this student is Slytherin and dra interestingly enough at least according to the internet has no Patronus was never revealed in the books or the movies so it turns out this is actually a wonderful teachable moment there is a special keyword in Python that is literally none n o n e with the first letter capitalized this represents officially the absence of a value so I could a little sloppily do something like quote unquote but does that mean I didn't get around to typing it or not it's a little clear semantically to say literally none a special keyword in Python to make clear that I know uh Draco has no Patronis it's not just an oversight on my part now that I have this what do I have in the computer's memory I have a list how do I know it's a list because I see a square bracket at the beginning and another square bracket at the end that's just my visual clue okay I don't know necessarily what else is going on here but there's a list of something what is in that list well here two the syntax is our clue because this line two starts with a curly brace and ends with a curly brace I just know that is a dictionary a collection of key value pairs now this all fit on my screen perfectly so I didn't bother moving all of the key value pairs onto new lines it would have made it really tall so I I kept it all together here this time but how many keys does this first dictionary have put another way in her mayane physical dictionary how many words are in that dictionary three the words are name house and petronis what are the three definitions or values of those words in herm's dictionary Hermione Gryffindor and Otter respectively and the same story goes for Harry then for Ron then for Draco I have by Design chosen to give them dictionaries that have all the same Keys all the same names but they all have unique values and that's my design That's My Prerogative as a programmer so why is this useful at the end of the day now I have access to a whole collection of interesting data about all of these students and I can still do a loop I can say for student and students that's going to allow me to iterate over this list of students and let me go ahead and print out just one thing at a time let me print out the current Student's name so as complicated as the dictionary is this should be pretty comfortable four student and students is just going to iterate over every student in the list 1 2 3 4 total the next line is just going to print out the value of the name key it's like opening a physical dictionary looking up the word name and giving us Hermione Harry Ron and Draco respectively from each dictionary so if I run this version of Hogwarts and hit enter there I get all three of their names but what if I want more information than that I want both their names and their houses well just add to prints arguments student Open Bracket uh House close bracket all right let's go ahead and run this python of Hogwarts dopy and hit enter so I now see Hermione Gryffindor Harry Gryffindor and so forth well we can aesthetically clean this up a little bit by adding a separator with print like a comma in a space just so that when I run this again I now see some commas separating these values but recall that students have not just a name not just a house but also that Patronis so if we want to print out that too we now have the syntax via which to go into that same dictionary for each student and output their Patronus as well as their house and their name so if I run this program one final time now I see all of the data in this here dictionary so this is a lot to absorb all at once I'm sure it's the last of our new data types on top of lists we have these dictionaries but again a dictionary at the end of the day is just a collection of values similar to these values here that allow you to associate keys with values and the first version of this program Associated literally the students names with their houses but then I realized in my next version wait a minute what if every student has not just a name in a house but a Patronis let's actually standardize the names of our keys to be name house and Patronus and then the values of those keys can actually be the data like Hermione Gryffindor otter and so forth questions now on these dictionaries and iteration thereof I just was wondering if the suppose the dictionary is very huge and if I want to look up for a specific student so how do I know uh where to look that student from like can we sort it out in alphabetical order or numeric order or anything like that in short answer yes one of the features of python is that it makes these dictionaries very highly performant for you that is even if they're very large as they will be in future weeks when we manipulate more data python will find the data you care about quickly for you and in fact that is a feature of the language that is a feature of a dictionary to get you the data quickly and there are functions that you can use you can sort the data you can sift through it you can do very performant operations as we eventually will allow me then to propose as we wrap up these Loops that we solve just a few final problems that will perhaps evoke fond memories of yester here at least for me where in one of my favorite games growing up was this one here on the original Nintendo and this is a two-dimensional world where the characters move up down and right not so much to the left in jumping over pyramids and obstructions like these and allow me to propose that we use this just for inspiration not to do something that's quite as colorful or graphical as this but just to focus on for instance this barrier in the middle of the world here that Mario or Luigi had to jump over and so this here seems to be like three bricks stepped on top of one another and we won't do things quite graphically but let's just Implement a very simple python based version of this textually using maybe just hashes for bricks because there's a pth pattern here one on top of the other and I bet we can solve this in any number of ways well let me switch back over to vs code here and let me propose that we create a program called mario. using code in the terminal window and then up here let me start by implementing that same picture as simply as I can printing out just literally the hash and then the hash and then a third final hash this is going to be a very textual approximation of it but I think if I run python mario. I've got a very simple version of that same column of bricks so to speak but you can imagine that certainly in a game where maybe these uh The Columns get higher or lower it would be nice to write code that's actually a little more Dynamic than that and doesn't just use print print print which is literally copy and paste it would seem so let me at least adopt some of today's Lessons Learned and instead do something like this for underscore in range of three let's now print out just one of these at a time but the fact that I've now used a three to range means if I want to change it to something bigger or smaller I change it in one place not in three or more places and this code two of course if I got it right is just going to print out the exact same thing so we're iterating here but let's see if we can't now integrate our discussion of writing functions of our own to begin writing something a little more Dynamic and solving more complicated problems ultimately one of the nice things about functions is that they allow us to not just write code that we can use and reuse they allow us to create abstractions if you will an abstraction is a simplification of a potentially more complicated idea and we've seen this a few times over the course of the weeks for instance we had a function called hello which granted didn't do all that much it just printed hello but it allowed me to think about the function as exactly what it does not generically printing something but literally saying hello I've been able to get a number using something similar by defining my own function like get number well let me go ahead and for instance assume for the moment that I've had the forethought to uh in my function main use a function called print column that seems as good a name as any to use a function that prints a column of bricks well how can I go about now implementing this abstraction this simple idea print column with actual code well we've seen before with def we can do just that let me Define a function called print column let me accept as its input uh generically speaking a parameter called height I could call it n or H but I'll be a little more explicit now with height just so I remind myself what it's doing and now I think I can just borrow some of that same code from before for underscore in range of height go ahead and print out a single hash and then at the end of this whole program let's just call Main so I've kind of complicated the code it doesn't do anything more just yet but it's setting me up for solving what I think are going to be more sophisticated problems if I run python of Mario up high we're back where we began but I now have a function an abstraction print column that's going to allow me to think about printing some chunk of the world of Mario at a time and I can do this in different ways too notice that if I really want I could do something like this I could reimplement now print column in different ways especially if I am using print column all over my code or maybe still a colleague of mine a friend someone else on the Internet is using my print column function what's also nice about functions you've written is you can change the underlying implementation details of them but so long as you don't change the name of the function or its parameters or what it returns if anything no one else knows the difference you can change the internal implementation as much as you want if you want to improve it or make fixes over time so for instance another way we could Implement print column recall would be something like this a bit clever with one hash and then a new line and then maybe we could do multiplication strings and then end this line with quote unquote again it's okay if you're not comfortable with this syntax this was a more clever approach we saw in the past but if I run python of myoy here I'll still see a column of three but what's important here is that main does not need to know that the underlying implementation of print column has changed well let's transition to a different dimension if you will and rather than print out just these vertical bricks let's fast forward in the game to this part of the world here at some part mar Mario encounters these bricks in the sky that if he jumps up underneath they become coins and so he he gains to a score but let's go ahead and focus only on those coins and let me propose that we print out oh just these four question marks here and let me go back to VSS code here and let me propose that within VSS code here just like before we try to abstract this away so let me go ahead and get rid of this version cuz we're now going horizontal instead of vertical with our output and let me just say well print row four times let me just abstract away the problem at hand I don't know yet how I'm going to print those four question marks but let's call it print row four and I'll assume I'll now solve this problem let's now go down that rabbit hole of solving the problem Define a function called print row it's going to take a width instead of a height because it's horizontal instead of vertical and how can I do this well now we have an opportunity to do string multiplication even more elegantly I can say quote unquote question mark times with and this is a very pretty pythonic way of printing what could otherwise be a loop and that's fine but this is going to go ahead and print those question marks for me let's do python of mario. enter and now I've got four question marks it's not nearly as pretty as the more graphical version but it is at least uh a building block toward having now a reusable function like print row and why am I doing all this like why are we over engine engering the solution to these problems by having print column and print row well it's a useful problem solving technique as soon as your world does not look one-dimensional like this or with the column version but what about this later in Super Mario Brothers does Mario have to jump down into this world where there's a lot of these underworld barriers and this one here for instance looks like a square it's two-dimensional there's a height and a width to it and that is to say there's a bunch of different ways we could implement this thing if maybe for discussion it's like a 3X3 grid a 3X3 square of sorts well how can we go about solving this here problem well let me propose we come back to vs code and let me propose that we think about this in a couple of different ways I could do this H like this if I if I know where I'm going you know maybe I'm a seasoned programmer let me go ahead and do this let me print out a square the width and the height of which is three that's an abstraction I'm just taking for granted for moment that there is already a function called print Square that's going to be width three and height three as well but someone's got to implement this and at the moment there's only me at the keyboard so let's go ahead and Implement that square let me go ahead and Define a function called print square that takes in a specific size both for height and for width and here's where we have an opportunity to use some of those loops and we can use those Loops in a way we haven't yet if I want to print out all of these rows but also all of these columns I now have to think not just cyclically like a loop allows but I need to think two-dimensionally and if you're familiar with like an old school typewriter or even a printer nowadays It generally prints from top to bottom so even if you have multiple columns you print out one line at a time and while you're on that line the printer or the typewriter prints from left to right and that's kind of the mental model to have with your black and white terminal window all of the output for every example thus far starts at the top and goes down to the bottom from top to bottom left to right so we have to generate our output our Square in that same way so let me propose that we do this let me propose that we know we need to iterate this many times three or more generally size so let me do this for I in the range of size what do I need to do three times Well I want to print out what one two three rows of bricks but within each row of bricks what do I want to print one two three bricks specifically so if we go back to our diagram here and I stipulate that it's indeed meant to be a 3X3 Square three wide and three tall what do I want to do to print the first row I want to print brick brick brick brick brick what do I want to print on the second row brick brick brick and the third row brick brick brick so I'm doing three things three times there's a lot of printing that must happen so so let me go back to my code here and let me propose now that we think of this outer loop that I've just started as representing each of our rows for I in range of size is going to ensure no matter what I do next that I can print out one two three rows or more generally size where size could be three but it could be smaller or larger what do I want to do on each of the rows well just like an old school typewriter or printer on each row I want to print out brick brick brick brick brick brick brick brick brick well that sounds like a cycle some kind of loop so maybe I can have inside of one Loop another loop I don't want to use I again because I don't want to use the same variable and mess up my counting so I'm going to by convention use J very common to use I and then J maybe K but after that you shouldn't keep nesting inside of each other let me go ahead and say for J in range of size two because it's a square and then each of these rows let me print out a single hash but no new line but after each row let me print only a new line so there's a lot going on here especially if you've never touched python let alone Loops but notice what I've done here too and I'll add some comments for clarity for each row in square for each uh brick in row print brick and here is where comments and more generally pseudo code can really help explain to yourself and others what your lines of code are doing on line eight I'm iterating from I equals 0 on up to side so 012 on line 11 I'm doing the exact same thing but using J from 012 but that's good because I represents now each of my rows and while I'm on each of those rows inside of this outer loop I'm going to do brick brick brick 1 two 3 1 2 3 1 2 3 but I don't want my cursor to keep moving to the next line while I'm on a row so I'm just overriding that line ending but let me ask a question of the group now why on line 16 do I have a print here all by itself why do I have a print all by itself notice that it's below the inner loop but inside of the Outer Loop so to speak what is that loop on line 16 doing ultimately every time you finish a line you have to add a new line and at the end of it so print it prints a new line perfect I don't want a new line after every brick I only want to do that at the end of the row and that's why my comments now are perhaps enlightening notice that this Loop here is just iterating for each brick in in the row once I'm done with that inner loop so to speak once I'm done with these highlighted lines here to Evelyn's point I need to print out one blank new line and we've not done this before but when you call print with no arguments all you get is that automatic line ending the back slash end where the cursor moves to the next line so if I now roll go back to my terminal window and run mario. I think I should get a 3X3 square and it doesn't quite look like a square on my screen because these hashes are a little taller they are wide but it is in fact 3x3 but let me propose as we've always done here how we might tighten up this code further just for clarity sake let me get rid of my comments for a moment just so we can see how many lines of code we have total and let me propose that we maybe do this let me propose that you know what this inner loop especially if you're having trouble wrapping your mind around one Loop inside of another loop you don't strictly need it what if we do this trick again what if we print out out inside of the outer and only Loop each of those hashes times the number of times we want them right we draw inspiration from an earlier approach and we run python now of Mario same result but now print square is really nice and compact it has one explicit Loop and it's still printing out using string multiplication all of the hashes at once on that row if you like abstraction and you'd like to wrap your mind more around what the code is doing well let's do this if you're not quite clear on what's going on let's propose that you implement a function called print row passing in size and let me propose that this print row function it simply take in that width and print out the individual hash times that many times in other words here's an opportunity for abstraction whereby well what does it mean to print a row well when you're implementing print Square I don't really care what it means to print a row I just need to know that someone's taking care of printing the row you can kind of pass the buck to another function Al together and how does print row work well it could use a for Loop it could use this string multiplication trick this is a way to take a larger program and this is probably the most complicated one we've looked at thus far and to decompose it into these smaller components that once assembled achieve your final idea seeing no questions that's the end of our look at Loops in Python this ability to do things cyclically again and again and when we combine those with conditionals this ability to ask and answer questions and combine them with our functions and variables we really now have most of the building blocks we need to solve much larger much more interesting much more personal questions so in the weeks to come we'll start to see exactly what could go wrong though when we do so but we'll introduce you to all the more tools via which you can troubleshoot those same problems [Music] [Music] all right this is cs50's Introduction to programming with python my name is David men and this is our week on exceptions exceptions in python as well as in other programming languages refer to problems in your code indeed when something is exceptional in your program it actually doesn't mean it's a good thing it means something has gone wrong that ideally you will somehow solve so what are some of the things that can go wrong so I'm going to go ahead and open up VSS code on my computer here and in the terminal window I'm going to go ahead and run code of hello.py that's going to of course open up a brand new tab for me hello.py in which I can write my code and let me go ahead and write some very simple code just to say hello to the world let's go ah head and say print quote hello comma world and then let me go ahead and I'm forgetting to close that quote so a mistake that you yourself might have already made or might surely in the future make and it's a little subtle because you might not necessarily notice that you've just missed that one character well let me go ahead and somewhat optimistically go down to my terminal window now and run python of hello.py and hit enter and that's the first of my errors my gosh I've only written one line of code and I seem to have more lines of error errors on the screen but the Salient point is this bottommost thing here notice where it says syntax error a syntax error is a problem with the code that you have typed your syntax just like English and other human languages have syntax associated with them so does my code and it's not quite correct something is ay I didn't follow the instructions properly and it does elaborate for me unterminated string literal now that's a bit Arcane that is a bit of a confusing error message but unterminated would generally mean that I started something but didn't stop it I didn't terminate it string of course is a sequence of text like we've discussed before or stir in Python and literal generally refers to something that you literally typed it's not a variable it's something like quote unquote or just quote hello world so the fix here of course is going to be to go ahead and terminate that string and actually close the quote and if I now go back down into my terminal window and rerun python of hello.py now I'm saying hello to the world so the catch withd syntax errors here is that syntax errors are entirely on you to solve a syntax error is a problem that you've got to go back into your code and fix from the Geto you can't just kind of hope that it's going to resolve itself or expect that other parts of your code will catch it for you syntax errors just must be fixed but there's a lot of other types of errors in Python that might be described as runtime errors that happen while your code is running and it's really up to you to write some additional code defensively to detect when those errors happen because you don't necessarily know for instance what input humans are going to type into your program and so you better be ready defensively to accommodate things that they type or even mistype so for instance let's go back over here to vs code and let me propose that we take a look at a a new file Al together I'm going to close hello.py and I'm going to write code of say number. piy so let's play around with some numbers in Python and the first thing I'm going to go ahead here and do with number. py after opening the this new tab is I think I'm going to go ahead and print uh type up a relatively simple program that maybe prompts the user for an integer like X and then just prints out what x is so we're going to start super simple but again in starting simple we'll be able to really see where I've done something wrong well here we go I'm going to go ahead and say a variable called X is going to get assigned the value of the return value of input quote unquote what's X question mark and I'm going to include a space to move the cursor over a little bit and then ultimately I'm going to go ahead and oh wait a minute if I'm wanting to get an INT from the user recall that I need to do something proactively I need to actually convert that input to an integer using the int function in Python so now I'm passing the return value of input as the argument to in and that will store in X ultimately an integer not a string that looks like an integer all right let me go ahead now and just quite simply print out what this is I'm going to go ahead and print out uh quote unquote X is X but I don't want to literally say x is X I want to plug in the value of x so maybe the easiest way to do that is to surround it with curly braces and then if I'm using these curly braces and I want python to interpolate the value of that variable that is substitute what x actually is in between those curly braces recall that I need to use a format string or an F string by prefixing this whole thing with an F now that I've done that let's go ahead and see what happens I'm going to go ahead in my terminal window and run python of number. Pi I hit enter and so far so good all is well and being prompted for X let me go ahead and type in a number like 50 all right that seems to work program seems to be correct or is it what could go wrong in this program even though nothing did just go wrong but if I run it and run it and run it again during the running of my program what could still go wrong especially if I'm not the human interacting with it but some other Human Instead any volunteers here for this one what could go wrong and in what way is this program not really correct even though at first glance it seems so what what is an inter we code in in a integrated ID we can't code in a interpreter so I'm not calling an integer I'm still having trouble hearing you but what I think I heard is that if the what the user types in is not in fact an integer I can't just blindly convert it to an int if I'm not putting too many words into your mouth I think what I should perhaps do here is be a little defensive and let me see if I can't simulate exactly the problem that could go wrong here let me go ahead and run again python of number. piy let me try another number and in fact when testing your code generally it's a good idea to test Corner cases maybe numbers that aren't quite as plain as 50 or 49 or 51 let's choose some numbers that might be a little more interesting if only mathematically like zero all right Z seems to work my code still prints out that X is Zer what might be another Corner case to consider well let me go ahead and try a negative number that too is pretty different in spirit from 50 negative 1 okay that works too well let me try it one more time I've tried positive numbers negative numbers zero let me try something like a cat so literally C A typing in a string that doesn't even look like a number and yet let's see now what happens when I hit enter all right we'll see now we've got another kind of error it's not a syntax error because I didn't make a typographical mistake I didn't forget some piece of syntax I actually now have a error with one of my values and it's a value I didn't even anticipate the human me in this case typed it in long after I wrote the code so what does this refer to a value error well let's see what the explanation is invalid literal for INT with base 10 quote unquote cat now this to is a bit of a mouthful and unfortunately in python and a lot of programming languages the error messages are written for pretty comfortable program and of course when you're learning programming for the first time you might not be so comfortable with the programming language let alone the error messages but let's see if we can't glean some insight so invalid literal well again a literal is just something that's been typed in it would seem for INT what is int exactly well int is the function I'm using to convert the user's input to a corresponding integer base 10 that refers to the decimal system uh which is this the default that Python's using and it looks like at the end of the day what python really doesn't like is that I passed Cat quote unquote to the int function so how do I go about actually fixing this problem well I could just add instructions in my program maybe I could add a line of print telling the user more explicitly be sure to type an integer or please don't type cap please don't type strings of course the user might still not oblig they might not be reading the instructions so that too is probably not an effective strategy what we really want to do is write our code with error handling in mind we want to write lines of code that not only accomplish the problems we care about but that also handle errors that might unexpectedly happen and in general when programming programming defensively assume that the users aren't going to be paying attention or Worse they're malicious they're trying to crash your program so we want to handle as many errors as we can now how do we go about doing that in Python well it turns out whether you want to catch a value error or other types of errors as well though not syntax error python actually has this keyword called try and it's sort of aptly named if you want to try to do something in Python you can literally use this keyword and you can check whether or not something exceptional something erroneous has happened so using both try and this other keyword except can I go and try to do something except if something goes wrong I can do something else instead so let's consider how can I go about trying to convert the user's input to an INT except if something goes wrong well let me go back to my code here and let me propose that I now modify this example as follows let me go ahead and above my first line of code I literally write try and a colon telling python try to do the following I'm going to go ahead and indent my existing lines of codes here by the same number of spaces four in this case and then I'm going to add one more new line down here that literally says accept value error and notice it's important that I've capitalized the V and I've capitalized the E these uh symbols are case sensitive and this is now an opportunity after this colon to tell python what I want to do in exceptional cases when the number or the input from the user is not in fact a number and I'm going to say something plain like print quote unquote X is not an integer I'm at least going to tell the user roughly what the problem actually is so notice another detail the indentation is important because I have try on line one and I've indented lines two and three those are the two lines of code that I'm trying except if I see a value error line five because it's indented is what is going to get executed in cases of those errors let me go ahead now back to my terminal window and run python of hello of python of number. piy enter and let's go ahead and type in 50 again still seems to work and of course I'm trying and succeeding let me go ahead and try once more this time though with the word cat or really anything that's not a decimal number and now you'll see much more cleanly X is not an integer I'm not seeing some scary error message that I of a user am have going to have no idea how to handle now you the programmer have anticipated that something exceptional can happen and you've gone about actually handling the error for the user giving them an appropriate error message instead let me pause here and see are there any questions now on what we've just done by introducing try and accept to handle this value error is value error the only type of error you can get or the other types is value error the only thing you can catch there are other errors as well and we'll a few of them today and there's many many more honestly that if you continue programming and programming in Python you're going to see a lot of them over the the weeks the months the years to come but the technique for handling them is going to be largely the same other questions on try accept or these exceptions more generally uh yes sir actually to use the accept log you need to know the type of error right like here you knew it was a value error what what if you can't anticipate this particular type of the error a really good question so I'm being very good about catching so to speak the very error that I know might happen I don't know when it might happen because it's going to depend on the user but I know what kind of error will happen from the int function there is a way in Python where you can say except if anything goes wrong and you can literally omit value error and just catch everything the problem with that is that it sometimes hides other bugs in your code because you don't necessarily know what's going wrong and if you don't necessarily know what's going wrong how can you possibly handle it correctly so bad practice and it put another way it's lazy to do that to just say catch everything and I'll deal with it here so a much better practice would be to figure out what kind of Errors could happen and include mention of them explicitly as I've done now with that said if you read Python's official documentation as you'll eventually invariably do it is not great about telling you proactively what kinds of Errors can be raised in this way so it's a bit of contradictory advice you should do it this way but it's not always obvious what you should be checking for but you get better at it with practice and some of the times the documentation does spell out what could go wrong let me turn our attention now back to this and point out that even though this is better code it is more correct in the sense that I'm not just leaving it to the user to see some really ugly default python error message that most people are going to have no idea what to do with I'm at least handling it more elegantly and I'm printing out X is not an integer so it's at least more instructive but this isn't necessarily the best way to implement this code why well here too I'm actually still being a little lazy so notice that I'm trying to do not one line of code but two lines of code and this isn't a huge deal because we're only talking about two lines of code but in the interest of PR uh preaching best practices you should really only be trying to do the one or very few lines of code that can actually raise an exception that can actually fail in some way I am pretty sure that calling print here is not going to raise a value error whether X is an INT or a string or a float or anything else the format string feature of python is going to handle printing it just fine so really what I'm going to do is this I'm going to move this line three down to the bottom of my code I no longer need to indent it I'm just going to execute it at the bottom of my file here unfortunately by doing this I've done a good thing by now only trying to do the minimal amount of work necessary that might raise the exception a value error but I fear I've introduced a new mistake well let's see what is now in correct let me go ahead and again run python of number. enter let me go ahead and do it correctly with 50 and all seems to be well but again let's try those Corner cases the zeros the negative numbers or in this case the cat let me go ahead and type in C A again enter now I have a name error so now it's yet another type of error in my code that I've introduced here and what is this name error mean well just as a value error refers to that the value of some variable the value that someone has typed in is incorrect name error tends to refer to your code like you're doing something with the name of a variable that you shouldn't and why might that be well let me turn our attention back to the code here and consider what is it complaining about well the name error is what I see down here and it's telling me name quote unquote X is not defined and notice if I look further here it is mentioning line six so I know the problem is with my code on line six and that worked a moment ago and I'm defining X on line two but let me ask the group here why does X not in fact exist on line six why is it not defined even though I'm pretty sure I was intending to Define it on line two maybe the scope of the variable is between the tri block so good terminology scope refers to the portion of code in which a variable exists that to though isn't quite right in Python that would be true in cc++ in Java where indentation or curly braces tend to define the scope of a variable but again here in general and this worked a moment ago X exists once it's defined on line two because remember I printed out X is 50 a little bit ago let's try one more hypothesis here one more hand why is X somehow still not defined um yeah so is it because it's loo variable meaning that like it doesn't Define outside of scope CU like what people have mentioned it's it as it promps it input in try right but outside of it it's undefined so still good instincts in good terminology too there's this notion of local variables which tend to exist inside of functions for instance Global variables which tend to exist in entire files in this case too though that's not quite the case What's Happening Here boils down to order of operations let me come back to the code here and recall that anytime we've discussed the assignment operator the single equal sign that copies a value from the right to the left but consider for a moment at what point something is going wrong well the input function is probably working just fine because we've used that a lot now to get users input it always returns a string or a stir in Python but what could be going wrong well if I'm passing that string to the int function as its argument it's probably the int function that's airing and indeed if you think back earlier when we had the value error it was in fact the int function that did not like quote unquote cat as input so this is all to say that this portion of my code highlighted now to the right of the equal sign that's the code that's creating a problem that's the code that was creating a value error and in this case we're catching the value error but because the value error is happening on the right of the equal sign there's no value being copied to the left the error is interrupting that whole process so even though we see x equals dot dot dot on line two the portion of that line to the left of the equal sign isn't getting evaluated ultimately because the value error is happening too soon and so when we finally get down to line six even though it looked like I was defining on line two and I would have defined X on line two if all had gone well we didn't get to the part where the value is copied from right to left because the value error happened first so this code is just incorrect now so how do I go about solving something like this well it turns out that there's another feature of the try and accept syntax that python supports which is that it also supports the keyword Els now we've seen Els before if you think back to our discussion of conditionals we saw if we saw L if we saw Els which was kind of this catch all what you should do in the event that nothing else is relevant that's kind of the same intuition here for the TR accept feature of py what you can do is this you can try to do the following as I've done except if this goes wrong but if nothing goes wrong else go ahead and do this so this is one way I can solve this same problem now no matter what now python is going to try to execute line two if something goes wrong it's going to execute lines three and four to handle that value error however if you try and this code succeeds then there is no exception to to handle so you're then going to execute this line here so it's a little confusing perhaps in that we're now using Els both for conditionals if L if L if L if Els and we're also using Els with these Tri accept blocks but that's okay that's part of the language that's one of the features so now if I rerun this code in my terminal window python of number. piy let's do something correct like 50 I see that X is 50 so line one is executed we're trying to do the following line two is executed because the conversion happened successfully and the number 50 gets copied from right to left the exception does not happen so we ignore lines three and four we jump immediately to line five and six which prints out the result by contrast though let's do this one last time python of number. piy let's type in cat or again any other word and hit enter now we don't see what x is rather we see quote unquote X is not an integer which is what's being handled in my except Clause all right let me pause here because that's a lot of new syntax and see here if there's any questions on try on accept on else name error or value error can you please repeat try function repeat the name error what's the problem with the name error yes yes yeah so let's let's just rewind a couple of lines here before I fix this problem by now getting rid of the Els a moment ago we had code that looked like this whereby I was getting a name error python of number. piy enter typing in cat that looked like this where name X is not defined and the problem was on line six according to this output in Python well let's think about this now deductively let's try a different approach on line six I'm seeing an error that name X is not defined okay Python's already telling me X does not exist at that point so how could that possibly be well where should X be defined well presumably X is defined on line two up here so what could go wrong well if the user has inputed something that doesn't look like a number like the word cat passing cat the return value of input as the argument to int to convert the word to an INT makes no sense you can't convert a cat C A to an integer at all so the int function is raising a value error at that point and the error is being handled with this code here but notice this line six is not indented it's left aligned with the rest of my code which means no matter what line six is going to execute it's going to execute whether I typed in 50 or I typed in cat but if I typed in cat again X never gets a value so it's not defined here on line six so when I introduced finally the Els statement that makes sure that these things are mutually exclusive I only execute the Els if I tried and succeeded up above well let me propose that we we refine this just a little bit further as well and consider how we might improve this example a little bit more it's a little it's a little unfriendly of me to be rejecting the user's input after they fail to provide an integer and just quitting the program really right it'd be more userfriendly if I just prompt or reprompt the user again and again and in the chat if you could what's the feature of python that you can use if you want to do something again and again and again until such time as the user cooperates and gives you what you're looking for like a number so yeah loop loop loop so a loop is something that happens again and again and again and maybe we can use that same mechanism a loop in order to prompt the user for x and if they don't give us a number prompt them again and if they don't prompt them again and again and again we don't need to just quit out of the program so quickly so let me propose this let me propose here that I improve this code by deliberately doing this let me induce a infinite loop at the very top of my code with while true recall that the while keyword induces a loop a cycle that behaves like this and it asks a question a Boolean expression that needs to evaluate either to true or false well if I want this thing to Loop Forever at least initially we'll just say while true because true is true so this has the effect of doing something no matter what forever unless we break out of it early now I'm going to go ahead and do this I'm going to go ahead and move my triac C code indented underneath this Loop so that I'm trying to get an X if I have a value error instead I print that X is not an integer but this time what do I want to do if the user does try and succeed in giving me a number well I can do this I can just break out of my code here and down here now I can use that same line of code from before an F string that says X is and then in curly braces X again so what's going on here I think this codee now because I've added the loop is going to have the effect of trying at least once maybe a second time maybe a third time maybe 500 times until the user finally gives me what I want which is an integer and once they do once there's no value error happening then I break out of the loop and line nine executes as I would hope so let me go ahead and try executing this version python of number. piy enter what's X let me go ahead and type in the easy thing first 50 x is 50 what just happened in terms of the control flow of this program the flow of my logic well I first found myself on line one inside of a loop hopefully I'll get out of this Loop what did I then do on lines two and three I tried to get input from the user and convert it to an INT well I was a nice guy this time and I typed in 50 which looks like and is a number so the int function converted it just fine and stored it from right to left in X except value error there is no value error because if I typed in a number there's there's nothing exceptional happening this is a boring good execution of my program so what happens I break out of the loop so again the else Clause is associated with the try not with the accept and once I'm out of the loop of course I'm just printing out what x is well let's try the other scenario that might happen python of number. piy enter what's X let's try cat or any other word enter ah this is now a new feature I'm being informed what I did wrong X is not an integer so I'm getting some useful user feedback but notice again I'm prompted what's X well let me try typing in dog X is not an integer what's X let me try bird enter X is not an integer what's X and suffice it to say this will happen now forever if I'm in an infinite Loop until I try and succeed at which point I break out so let's try again 50 enter now I'm out of the loop and I'm printing out what x actually is all right let me pause here and see if there are any questions the logic is almost the same but what is different now is I'm in a loop and I'm using the keyword break in Python to deliberately break out of the loop when I'm ready to once the user has cooperated do we really need to break can't we just print or what what keeps us from just printing uh good question so let me try that couldn't I just print well let's see what happens if I do that let me move this print line at the end in into my Loop here thereby shortening the program and in general that's been a good thing python of number. piy enter let me go ahead and type in 50 okay X is 50 what's x uh okay maybe it's 49 x is 49 uh okay maybe 48 unfortunately I think you're you're laughing you see it I never break out of the loop which maybe that's a feature maybe you want this to be your program but I didn't I'd eventually like this game to stop so I need to break out in that way but I can do it a little differently and let me propose that we modify this a little bit but first any other questions on this syntax here let me rewind to the prior version he uh can I use break uh all in exception except in else for example in another uh print and when you use print in the else you can use print together with break or something like this yeah you so you can use break inside of Loops to break out of loops and you can use it inside of a conditional like an if an L if or an else you can do it inside of a try accept else statement too anytime you're in a loop that you want to break out of you can use this keyword break I'm using it in the context of exceptions but it's not restricted to that and let me show you too it doesn't even have to be in the Els if I wanted to I could actually do this I could get rid of my elt and I could go back to line three add another line that's indented line four and break out here now why is this logically okay well well consider what I'm now trying to do I'm trying to execute line three and converting the user's input to an INT and I'm trying to store the result from right to left in X if something goes wrong the code we've already seen is immediately going to jump to line five and then six to handle the exception but if nothing goes wrong my code presumably should just keep on executing line by line so I could technically logically put the break here and watch what happens when I run this version python of number. Pi 50 enter it worked I broke out of the loop now which way is better honestly I think it could go either way at this point this program is so relatively short that even though I'm trying to do two things now one of which the break is not going to fail like you either break or you don't there's no piece of data from the user that's going to influence that we don't strictly need to have those two lines of code there but it's only two lines so I think it's okay and if you recall our discussion in the past not just of correctness does the code work as it should but design I think you could argue it either way if you prefer the readability of this and the fact that you don't have an El that's fine if though you prefer to minimize just how many lines of code you're trying to execute in case something goes wrong the else is a reasonable approach too well allow me to propose too now that we refine this further I think we're at the point where it's pretty darn correct but suppose now that I find myself today and tomorrow trying to get numbers from the user quite a bit it would be nice as we've seen to maybe just invent my own function get int to get an integer from the user both today and tomorrow and Beyond and heck maybe I can even share that function with other people if they want to write programs that get integers from users so how might I go about doing this well let me go ahead and propose that we do this let me get rid of the print line but keep most of my Loop here let me Define a function called get int that takes no arguments for now and I'm going to go ahead and indent all of the code I already wrote underneath get in so now I have a function called get int that tries to do the following try to get an in from the user if something goes wrong and there's a value error yell at them with X is not an integer else break but it's not just breaking that I want to do here now that I'm in a function recall our discussion of return values if you're inventing your own function whose purpose in life isn't just a print something on the screen like a side effect but is to hand back a value to hand you back value like on that same Post-It note from our discussion of functions well you need to return X explicitly how do I now use this function well as soon as we start making our own functions it tends to be convenient to Define our own main function as well that's the main part of our program and I'm going to keep this simple I'm now going to say x equals get int and then on the next line I'm going to do that print from before quote unquote X is in curly braces X and at the very bottom of my program recall I'm going to call Main so that no matter what I'm invoking my main function after everything's been defined well let's see how this works let me go ahead and run python of number. Pi enter let's type in 50 and it seems to work as before let's go ahead and run it again typing in cat C A this time X is not an integer and I'm being prompted dog and I'm being prompted bird and I'm being prompted fine fine fine 50 that's an INT and so it is printed so what's worth noting here well I'm manifesting a couple of good properties here one I've kind of abstracted away this notion of an getting an integer and even though I just artificially hit enter a whole bunch of times just to hide that function for now it needs to be there but we don't need to see it at this point notice that now this entire program really boils down to just these three lines of code now why because I've abstracted away that whole process of getting an INT from the user into this new function of my own called get int but can I improve upon this well let me go ahead and undo all of those blank lines and pull this up just so we can see more on the screen at once can I tighten up my implementation of get int it is correct I claim this is correct it's handling errors and it's returning X but I don't strictly speaking need to write the code as long what else could I do well let me propose that if all you're doing on this line 13 is breaking and then immediately after that per the indentation you're executing return X on line 14 why are you wasting everyone's time once you know you're ready to return the value you could just return X and so in my else I could break out and return a value so here too return is used to return values from functions break is used to break out of Loops but it turns out that return is sort of stronger than break it will not only break you out of a loop it will also return a value for you so it's doing two things for once if you will but can I make this even more compacts if if if my goal is to just tighten the code up even though it's already correct can anyone think of a further refinement whether you've programmed in Python before or not can I shorten this implementation further just a little bit if only to decrease the probability that I've made a mistake by having fewer lines and just make it a little easier to read because it's shorter any suggestions for tightening up my implementation of get int you can just return the value on the try function when you're trying uh at you take you take the input X and then done X good we can just return x a little higher up and let me correct folks as we go it's not a tri function it would be a tri statement technically a function typically has a parenthesis and another one in this case it's just a statement so but we can do exactly that I don't technically need the else if I really want I could do this right after line nine I could return X here or recall our discussion of defining variables unnecessarily sometimes like why Define a variable here if you're immediately going to use it here and then never again so we could avoid a new line here and I could avoid even defining X explicitly I could just say something like this I could return int input quote unquote what's X I can do it all at once now which is better I don't know I mean again this is where reasonable people might disagree I'd argue that on the one hand we're tightening up the code we're using fewer lines it's easier to read lower probability that I've made a mistake on the other hand it's a little more complicated to understand perhaps it's a little less obvious where I'm returning from so I think arguments can be made either way at the end of the day what's important is that you've done this consciously you've made a decision to do it this way or this way and you can justify it in your mind not that your answer is uh it worked so I left it alone like have a good reason come up with a good reason and that will come with experience and practice well let me propose too that we make one other refinement here suppose that you're finding your programs to be a little noisy and it's a little obnoxious that you keep telling the user X is not an integer X is not an integer X is not an integer what if you want to make things a little gentler and just prompt the user again with the same words what's x what is X what's X again and again well you can do that as well and it turns out that if you want to handle an exception in Python but you want to pass on doing anything with it so you want to catch it but you essentially want to ignore it you don't want to print anything you don't want to quit the program you just want to silent ently ignore it like if you're talking in a gr full of people and you're it's your turn to talk and you're just like pass they're still calling on you but you're not doing or saying anything more well we can add this keyword to our code here let me go back to my program here and instead of printing out again and again X is not an integer I could just do this I could pass on handling the error further I'm still catching it so the user is not going to see a scary message even mentioning value error my code is catching it but I'm passing on saying anything about it I'm going to stay in the loop I'm going to stay in the loop and keep prompting and repr prompting the user so now the effect looks a little something like this python of number. piy let's type in cat what's X again let's type in dog what's X again type in bird so it's just a little maybe more user friendly and that you're just reminding the user what you want maybe it's worse maybe it would be helpful to tell the user why you're prompting them again and again it's not obvious so it could go both ways but again it's just another mechanism now for handling these errors we use the accept keyword to catch a specific error but we don't have to handle it more than that we can just pass on doing something further let me pause here and see if there's any questions now on try accept else or pass okay yeah know I was just kind of curious I guess about uh the idea of when you were indenting with uh the get in function for example um because I'm noticing you know obviously going through it with the whole logic and breakdown the entire uh the entire function you know while true do this but I'm just kind of curious on elaborating with the indentations for the uh code more yeah so the indentation is deliberate logically some languages don't require as rigorous indentation you can use curly braces or other symbology to make clear what is associated with what in general anytime you indent something in Python on this line so rather anytime you write a code a line of code in Python that's here and the lines below it are somehow indented that means that those lines are somehow associated with that first line and presumably those indented lines should only be executed if the first line told the uh uh told the computer to do so so concretely what does this mean on line six here we're defining a function called get int that takes no arguments colon everything that's indented by at least four spaces Hereafter is part of that function why that's just the design of the Python language frankly I think the designers got tired of seeing really ugly code in languages like C and C++ and Java uh that uh don't necessarily enforce uh indentation to this extent so now it's baked into the language and my chronology might be a little off there but there's been many languages that are looser than python when it comes to indentation the indentation is Meaningful on line 72 notice that because the while true is indented by four spaces that just means it's part of the get in function but notice below the while true statement there's eight there's 12 there's eight there's 12 spaces here and I'm just quickly counting the dots that means that all of the lines I've just highlighted are inside of that while loop while true means to execute lines 8 through 11 potentially again and again and again and now lastly on line eight because we have try and indented below it is line nine that just means that what you should try is what's on line nine and similarly on line 10 below it we have indented line 11 you should only pass when there is an exception of a value error so the indentation just means what is associated with what and once you get comfortable with that you'll see that it helps the indentation alone helps explain the logic of your program and it has a wonderful side effect that for yourself the next morning for your colleagues your family your friends your teachers your code is much more readable as a result it's not one big mess of a blob of text other questions now on try except else or pass yeah thanks um two question uh question one um uh once you say pass can the caller still um learn anything about this error um through a system variable or whatever and question two problem set zero referenced some string Methods including is numeric is it any different to um go via isomeric here good question so on the first question if I'm handling the error in this way the caller is not going to know anything about it that's the point of my handling it so that Maine or other callers don't know that anything technically went wrong on the second question is numeric is another function that you can call that can look at a string and determine is this in fact a number I could use a mechanism like that I could use a conditional if this looks like a number then pass it to the int function and go ahead and convert it to an integer that's totally fine I would generally say that the pythonic way of doing things is often For Better or For Worse to try things hope they work but if they don't handle the exception so other languages are more in favor of checking if if if if L if else and all of these conditionals python tends to be a little more of the mindset eh try it but just make sure you're handling the error so this would be the pythonic way of doing it your way though checking with a conditional is it a number first is totally reasonable too if you want to go that way well let me propose some final refinements to this program that really just kind of tighten things up one additional step to improve the implementation of this get in function let me propose that we not hardc code so to speak that is type manually X all over the place let's make this function get int a little more reusable right now notice that I'm just kind of using the honor System that well main is defining a variable called X and get int is asking for a variable called X but it would be nice if the caller main doesn't have to know what the call is naming its variables and vice versa so caller to call a function means to use it the caller is the function that's using it the call E is just the function being called it would be nice if I'm not just hoping that X is the same in both places so let me propose this let me propose that we actually add a parameter to get int like this what's X that is to say if main wants to use the in function well then main should probably tell the get in function what prompt to show the user just like the input function recall that comes with python it's up to you to pass in a prompt that the user then sees when the human is asked for input so how do I make this work here I can go down to my definition of get int and I can say all right get int is going to take a parameter now called prompt I could call it anything I want but prompt in English is pretty self-explanatory it means what do you want the message the user will see and now down here when I actually use input I don't have to presumptuously say what's X because what if the program the caller wants to ask for y or Z or some other variable I can just pass to input whatever prompt the caller has provided so now I'm making more reusable code it still works just the same I haven't changed the functionality per se but now it's a little more dynamic because now get int doesn't have to know or care what variable is being asked for what's being asked for it just needs to know what prompt it should show to the user so if I now run this program down here again prompt number. piy enter what's x 50 still seems to work let's run it again let's type in cat it still seems to work and if I type in cat dog bird or anything else it will keep prompting me with that same prompt making this code therefore all the more usable now it turns out too you can even raise exceptions yourself using Python's raise keyword but more on that another time so in the coming days the coming weeks the coming months as you write more code in Python you'll see that errors are inevitable sometimes there's syntax errors which you got to just fix if you even want to run your program at all but they could be name errors for instance variables that you meant to Define but somehow didn't value errors where maybe the user didn't cooperate and provided you with something that you weren't expecting or a whole list of other possible errors or exceptions but now hopefully you know how you can handle these errors and respond to them in any way you like this then was our look at except and we'll see you next [Music] [Music] time all right this is cs50's Introduction to programming with python my name is David Meen and this is our week on libraries so libraries are generally files of code that other people have written that you can use in your own programs or a libraries code that you've written that you can use in your own program but maybe not just this program but another and another as well so python supports exactly this idea this ability to share code with others share code across your own projects and it does so by way of what it calls module a module in python is just a library that typically has one or more functions or other features built into it generally the purpose of a library or a module specifically is to encourage reusability of code if you find yourself using the same types of functions again and again the same functionality if you find yourself copying and pasting from an old project into your new project odds are there's an opportunity there to factor out that code that you keep copying and pasting that you keep reusing and put it into a library that you can then load into your programs moving forward so as to not just copy and paste it and have all these different copies all over so what are some of the modules or libraries that python comes with well python comes with a random Library literally which is to say that when you install the python interpreter on your Mac or PC or somewhere in the cloud not only do you get python you get a whole bunch of modules as well now these modules provide you with functions that you don't have access to just by default like you do print and input print and input and other such functions just work in Python but sometimes functions are tucked away in these modules so you have to be more deliberate about loading them into the computer's memory so somewhere on the computer's hard drive once you've installed python there is also it turns out a file probably called random. py that someone else wrote probably long ago but that you have access to and in that random. piy file there's probably one or more functions that you yourself can use in order to do things randomly that is to say how could you flip a coin in a program in Python how could you pick a a random number between 1 and 10 in Python well you need a bit of Randomness and while you could figure out mathematically how to write functions like that yourself it's a lot easier to stand on the shoulders of others who've already solved that problem for you so you can focus on the problem that you yourself want to solve so for documentation on most any python module you go to the official python docs and you go to a URL like this where the documentation for that specific module lives and within the documentation you'll see a list of the functions or other functionality that some module provides but how do you go about loading a module into your own program so that you can use the functions in that module well we need a new keyword in Python and namely it's import the import keyword in Python allows you to import the contents of the functions from some module in Python well how might I go about using using this in practice well let me propose that there exists in that random module this function among others so I have copied and pasted from the documentation uh this uh summary of a function called choice now the function exists in the random module so to speak not a random module the random module and so generally the documentation describes it fully like this random. choice is how you would technically call this function though we'll see alternatives to that in parenthesis there is a parameter called seq for sequence and sequence generally means a list or something that is list like if you have a list of numbers or strings or anything else and the documentation elaborates well how can I go about using this function to solve perhaps a a familiar problem well let me go ahead and open up vs code here and let me propose that we Implement a program that simulates flipping a coin a coin that in the US heads heads or tails the idea of which is to pick a decision with 50/50 probability 50% probability of heads 50% probability of Tails or you can use some other mechanism like that well let me go ahead and open a program with code called generate. piy because I want to start generating a whole bunch of random information the first of which is just going to be a coin toss now how do I go about using that function well I first have to import the random Library so literally the first or among the first lines of my file should be import random and that just gives me access to all of the functions in that specific specific module now suppose I want to flip a coin well I can do random. Choice per the documentation a moment ago and that again takes a sequence what's a sequence it's a list or something that's list like and we know about lists we've used lists to iterate over numbers we've used list to iterate over students at Hogwarts let's go ahead now and list iterate over just a list of two sides of a coin heads quote unquote or tails now I could call these anything I want these are my strings I just want to simulate tossing a coin so I'm just going to say in all lower case heads and tails but notice the syntax I have heads and tails in double quotes that's because they're strings I could also use single quotes so long as I'm consistent there's a comma between them which means the list has two elements there's square brackets to the right and the left which indicates that this is indeed a list that's the syntax recall for defining a list in Python and then lastly there's something more familiar there's the parentheses outside of those square brackets but those are just the parentheses that belong to the choice function and specify where its parameter gets passed in but again unlike ped functions I have to specify what module this function is in at least for now and so I do random. choice to call this specific function all right well it's one thing to flip a coin picking between those with 50% probability and that's what random. choice does it takes in a list and it returns to one of those values randomly with equal probability because I've passed in two items I've got a 50/50 chance if I passed in three items it'd be a 33% chance for each of those items and so forth python does the math for you but I want to store the value of this in a variable so let's Define a variable called coin equals whatever the return value is so this is indeed like flipping a coin I'm going to store in a variable called coin whatever that value is heads or tails and now just so I can see what's going on let's go ahead and print out the value of that string coin all right let me go ahead now and run this program in my terminal window python of generate. P enter and it looks like the first coin toss was the heads let's go ahead and run it again and it looks like it was heads again maybe you want to chime into the chat here if I run it a third time what's it going to be this time if you want to type your thoughts in the chat you might think there's a bug here but this is probability in action if I go ahead and hit enter a third time there it's actually now tails and again tails and again tails and again tails and again tails and again heads now if we did this in infinite number of times it would indeed work out to be 50/50 if we only do it a few times it might not work out as cleanly but that's how probabilities indeed work all right so I've got that now working could I have implemented this in a different way well let me show you an alternative to actually using the import keyword alone and let me introduce the keyword from in Python so from is a keyword in Python that you can use when importing functions from a module but it allows you to be a little more specific than import Al Lo so if I go back to my code here it's worth noting that what technically I'm doing here by importing random is I'm technically importing everything that's in that module so not just the function called random. choice but a few other functions as well so instead of using this line of code at the top of my file import random which will technically give me access to all of the contents there in a downside of that is that I have to type in random. choice random. this random. that because all of the functions I'm calling have to be associated with the scope of that module well suppose that I just want to call the function as its name choice I can do that as well let me replace this first line here with from random import choice and what this does effectively is it loads the functions name Choice into my current name space into the scope of the file I'm working in what that means is that I now know longer have to specify Which choice function I mean I can just say choice and so it loads it into the local namespace that is into my local vocabulary if you will so I can just now say choice this might be advantageous in what cases do you think when might you want to import the name of the function explicitly like this as opposed to just saying random. choice random. choice throughout your code when calling a function any instincts here for this alternative import using from um hello I'm Mohammed from Egypt and maybe if we have a variable that its name is basically like choice if I have a variable called the choice so I need to differentiate Which choice I choose so I'm gonna choose random DOTA Choice yeah really good instincts by using the first approach by just importing random you're making sure that all of its contents are associated with are scoped to the random module so that you can have your own choice function you can have your own choice variable you can use the same names as all of the functions or variables that are stored inside of that file without them colliding so to speak and this is a good thing in older languages it was the case that if you imported someone's Library you better hope that you're not using the same functions or variables as they are because you might in fact have some kind of conflict Python and certain other languages allow you to scope the names of those functions and variables to the file or the module that they come from so that's a good thing but honestly this is such a short program or equivalently maybe I'm using the choice function in so many places calling random. choice random. choice random. choice it's just making my code longer and longer and longer marginally so but it just getting ugly and annoying I can simply import choice and now tighten up my code a little bit so as with so many decisions in the past there's not necessarily one right approach or another it depends but I think for those very reasons sometimes it's better to do what we did the first time which is only import the module so as to retain the scope therein well let me propose that we transition to to another function that comes with Python's random module and that's this here from the documentation Rand int it's a bit hard to say but it implies get back a random int and if you read the documentation it's a random int that's between A and B inclusive so if you were to pass in one for a and 10 for B you would get back a number between one and 10 inclusive including the one and including the 10 potentially each with a 10% probability so how might I go about using a program like this well let me come back to my generate. piy file and why don't we go ahead and try generating a random number between 1 and 10 you might do this frequently in the real world when you just want someone to pick a random number you tell them as much and the human responds let's get the computer to do the same here let me go ahead and delete my two lines of code at the bottom but keep my import random and let's go ahead and Define a variable this time called number set it equal to the return value of random. randint and now pass in a a value of one and B a value of 10 and now let's go ahead and print the number I'm going to go ahead in my terminal window and run python of generate. Pi and hit enter four python of generate. Pi and hit enter eight again nine again s again 10 again two again and we can do this all day long and if we add all of those up they should end up being with 10% probability each now how might you use this information well maybe we're playing a guessing game or maybe we're trying to randomize the behavior of some character in the game you can imagine using very simple building blocks like this just kind of spicing up your program by getting it to do things a little less predictably because you're choosing these values seemingly randomly and you're deferring to python to actually do the generation of these numbers uh using its own algorithms and its own math well what more could we do here let me propose that we introduce another function that comes from this random Library yet another that you yourself have don't have to implement Shuffle if you read the documentation for Shuffle in the same random module you'll see that it takes in a list for instance of values and just shuffles them up it randomizes them like a a deck of cards here you might shuffle them so it's to put them into seemingly random order well how do I use this based on this function's name well let me propose that we go back to vs code here and let me go ahead and this time do the following because I need to shuffle something like a deck of cards let me go ahead and not just import random but let me give myself a variable called cards that's going to be of type list and just so I have something to shuffle I don't need all 52 cards in a typical deck I'm just going to shuffle three cards a jack a queen and a king I could call those strings anything I want but I just wanted a list of some values so as to shuffle them up that is randomize the order therein well how does this now work if you read the documentation for random. Shuffle you'll see that it shuffles the argument in place that is unlike many of the functions we've seen it doesn't return to a value that contains the shuffled cards in this case it actually shuffles the list it's given itself so what this means for my code is that I need to do something like this random. Shuffle and pass in the variable containing those cards and then on a final line here how might I go about printing the cards well I could do this and I could say print cards but if I do that I'm actually going to see python Syntax for lists and it's just going to format in its own way using commas and the like I want to print these cards out one at a time just because I think it'll look a a little better so we can use some of our syntax from loops and say something like this for card in cards go ahead and print out the current card so what's now Happening Here line three I'm defining a list of three cards in this order Jack queen king I'm then shuffling those same cards on line four and then on line five I'm using a for Loop for each of the cards in that list print it out one at a time and because I'm using print one line at a time well let's see the results down here in my terminal window I'm going to run python of generate. and hit enter queen king Jack seemingly shuffled cuz that's not the order I defined earlier let's do it again queen king Jack H okay that happens to be the same but let's see this could just be bad chance there we go Jack queen king doesn't look like it's shuffled but at least we're getting back different orderings now again jack queen king hm not so good Jack queen king not so good this is someone you you probably want to play against with cards Queen Jack King there we go but of course we only have three cards here so there's not that many permutations we might see and if we do this over time we will see all of them but if we had of course 13 or 52 cards we'd see a lot more permutations instead so we have now these three ways to Generate random information one is simple coin toss if you want to start some kind of athletic event one pick a number between one and 10 if you want to decide something based on that and now using Shuffle we can even take in a list of things and shuffle them about so that we get some kind of random Behavior let me pause here and see if there's any questions yet on random on modules or any of these three functions yeah uh can we increase or decrease the probability uh of costs if you want to for example there is three there is a 33% chance of probability so is there any chance to increase or decrease the probability can you set these probabilities not using these same functions uh can you set the probabilities but you can absolutely Implement some of your own functions or use more sophisticated functions that do exist in this library and others to exercise more control these are meant to be very userfriendly and simple functions certainly the ones we looked at that give you equal probability for all of those but absolutely you could skew things though hopefully if you're implementing a gambling game or the like you're not actually making some cards more probable than others allow me to turn back now to our implementation here of this Randomness and consider how we might leverage other types of functionality that aren't necessarily in this specific Library here well it turns out that python also comes with a statistics library and this contains all sorts of functions for doing things more statistical in nature namely calculating means or medians or modes or other uh aspects of a data set that you might want to analyze so how might we use the statistics module on python well we might first just take a look at its documentation like any other module on Python and we'll see Within that library that there's a whole bunch of functions and one of those functions is one that's quite simple it's average a function that allows you to calculate the average of some numbers that you've passed in let me go ahead and nvs code in my terminal window open up a new file called average. piy and at the top of this file I'm going to import a different Library this time namely the statistics module in Python and now I'm going to go ahead and call a function that I know comes in that module namely mean for the average of some values and I'm going to call Stat statistics. mean and I'm going to pass into this function mean a list of some values and let's suppose that I'm quickly trying to calculate what my current grade average is in school and I did really well on my first test and I got 100% And on my second I did well but not as well and I got a 90 and ironically I'm not very good with math so I'd like to figure out what my average now is between those two tests so let me go ahead now and in this list type in the number 100 comma 90 thereby passing in a list of two values to ins one 190 and in outside of those are the parentheses because of course this is now the argument I'm passing to the function called mean and this function mean is in the module called statistics well it's not that interesting to just calculate the mean if I don't actually see what it is so let me additionally pass the return value of that mean function to the print function as usual let me now in my terminal window and vs code Type in Python of average. piy and hit enter and voila as you might expect my average is 95% so the difference here is that I'm just using a different module that still comes with python but I need to import it instead of for instance the random module instead and this time I know from the documentation that there exists a function called mean well it turns out there's even more functionality that comes with python and that comes with other modules in Python and there's this feature generally known as commandline arguments this is a feature not just of python but of languages more generally that allow you to provide input not when prompted inside of a program as happens whenever we call the python function input but rather there's this feature command line arguments of programs that allows you to provide arguments that is input to the program just when you're executing it at the command line so up until now for instance Rec call that we've generally run python of something. py for instance python of hello.py and I've never once really executed any words or phrases after the name of the file but I could in fact when you're running programs in a command-like environment like we are you can provide any number of words or numbers or phrases after the command that you're typing and all of those will somehow be passed in as inputs to the program itself you don't have to prompt the user for one thing at a time by manually calling that input function so what does this mean in real terms well let me go ahead back into VSS code here and let me propose that we consider how we might leverage a certain module I'm going to go ahead and create a file called uh name. pi and I'd like to use a new module this time that's going to give me access to values that have been typed at that command line but what's this module going to be well this one's going to be called CIS and CIS short for system contains a whole lot of functionality that's specific to the system itself and the commands that you and I are typing the documentation for this module is at this URL here and it lists all of the various functions and variables and the like that come with that module but we're going to focus on something a little more specific namely this thing here it turns out in the CIS module in Python there is a variable that just magically exists for you called argv it stands for argument Vector which is a fancy way of describing the list of all of the words that the human typed in at their prompt before they hit enter all of those are seemingly magically provided to you via python in a variable called cis.org V this variable is a list which means that the first element is going to be the first word that you typed the second element is going to be the second word that you typed and so forth and by way of this list then can you figure out what words did the human actually type at the prompt and maybe use that to influence the behavior of your own program so what does this mean now in real terms well in this new tab called name. piy let me go ahead and import CIS within that CIS module is going to give me access to cy. RV but how might I want to use it well let's do this instead of writing a hello world program that all of these times has just looked for the return value of input to figure out what the user wants me to print let's go ahead and just expect the user to tell us when they run the Python program itself what their name is and suppose this time I'd like to generate a whole bunch of name tags initially just one and in the US here it's very common to wear a sticker on your lapel that says hello my name is David so I want to print out some text that resembles that the idea being maybe I could enhance this program someday to even send that text straight to the printer and dynamically generate those name tags well let me go ahead now and do this let me go ahead and print out as always hello but I'll say a little something more this time to make things more interesting hello my name is quote unquote and then after that I normally have been in the habit of calling input storing the return value in a variable and passing in the name of that variable here but I'm going to instead jump right to this sis. RV bracket1 and that's it I'm going to have a program here that says hello my name is followed by whatever is in sis. arv bracket one and notice sis. argv again is a list and recall from our discussion of loops and in turn lists we use this square bracket notation to get at the various elements inside of a list all right let me go down now into my terminal window and run python of name. py but this time rather than just hit enter and wait for the program to prompt me for my name let me proactively just tell this prr program what my name is at the so-called command line here we go David separated with a space from the name of the file so that now when I execute python name. py David I see on the screen voila hello my name is David So based on this demonstration alone I think we can infer exactly what's going on in cy. RGV even though it sounds certainly at first glance uh rather complicated here let's look up at cy. Arvy I'm going to bracket one here so clearly cy. RV bracket one is storing David but it's one in the past when we looked at Loops recall that we said that they were zero indexed that is the first element is zero the next element is one the next element is two and so forth and yet here I am treating it as though my name is at the start of the list one well let me ask this question what is probably insist. arv of zero what is probably insist. Arvy of zero the very first element actually in that list oh yeah uh I think uh it's like in C uh the name of program indeed it's indeed like in C and other language is the name of the program well if we consider what it was I typed I certainly typed python because that's the name of my interpreter and we don't really need to know that because we're using python itself but after that I did type two things I typed name. as I've done so many times anytime I want python to interpret a program I've written and it turns out by convention what python does is it stores in cy. arv the name of the file that you're executing or interpreting followed by any number of other words that you type so all this time we could have been accessing the name of the program which frankly isn't all that interesting but we can also now access words that are typed after that prompt as well but of course if I don't type anything in what might happen here this might be naive of me to assume that there's always going to be something at location one in cy. RV let me go ahead and try this python name. pi and no I'm not giving you my name because at this point I might not even know that you want my name to be typed so let me hit enter now and uhoh we see now an error a so-called exception in Python this one's a new one this one's an index error that elaborates list index out of range and turns out this is actually one of the most common mistakes in programming whether using a list in python or arrays or vectors in other languages is to try to access some element that does not exist you try to go too far to the left or you try to go too far to the right in this uh in this object that is just a list of some values so of course the mistake here is that I'm assuming there's going to be something at location one when really it's location zero that's the only one that has a value but fixing this is not going to amount to doing bracket zero because now if I go ahead and rerun this program with no other words after name. it says hello my name is name. which is fine if we're making a name tag for the program but that's not of course what my goal here is instead so if the fix is not just to change the one to a zero how else might I handle this error how else might I handle this error this index error that happens if the user just doesn't remember to or doesn't know to type their actual name at the prompt we could always put an exception into the program saying if there is um if there's nothing at location one we just come out the say okay we haven't got a parameter or something but if there is we continue along with the program perfect so if I might simplify we can try to execute this line of code except if there's an error we'll deal with it in some other way now ideally and once I'm a strong enough programmer I would have anticipated this and written the following code from the get go but when you're learning it's certainly reasonable to see an error oh I didn't realize I should detect that and then go back and improve your code but of course if you read the documentation you ingrain some of the Lessons Learned From the Past you'll get into the habit of trying and checking for some of these exceptions yourself so let me solve this in one possible way as you proposed here let's try to handle this exception as follows let me go ahead now and instead of just blindly calling this print line let me try to print out hello my name is such and such except if there is an issue specifically an index error then what do I want to go ahead and do I'm going to say something like two few arguments I could be more explanatory than that but for now I'm just going to explain to the user that they gave me too few arguments too few words at the prompt so now it's still not going to work in quite the way I want I'm still not going to be able to generate their name tag but at least they're not going to see some cryptic error message and think that they themselves broke the program let me go ahead now and run python of.pi enter and too few ARG ments okay let me go ahead now and do python of name. and type in my name David and now we're back in business and I see that my name is on the screen too but strictly speaking I don't have to try to do this I could actually be a little more defensive in writing this code and maybe I could check whether or not the user has indeed provided a name or multiple names at the prompt so as to give them more refined error messages as well so how might I do this well let me go and and undo the exception handling I've added and why don't I instead more modestly try to do this let me go ahead and introduce a conditional here if the length of cy. argv is less than two or equivalently equal to just one value but I'll just stick with less than two for now then go ahead and print out two few arguments so I want ultimately two arguments I want the name of the program at location zero and I want the name of the human at location one so that's a total of two arguments so if I have fewer than two arguments let's tell the user with this print line L if the length of cy. RGV is say greater than two like they typed in too many words at the prompt well let's tell them print quote unquote too many arguments else if they did get it right and they gave me exactly two arguments else let's go ahead and print what I actually care about all right let me go down to my terminal window here and run python of name. and voila uh oh a completely different type of error this one a syntax error which we've seen in the past now a syntax error recall is May aopa like I messed up here and I wrote invalid syntax and so no amount of conditionals or exception handling is really going to catch this one I need to go back and just get my program to work because it's not running at all well let me go up here and see line four is the issue and indeed it looks like I have an unterminated string here I need to go ahead and now add this double quote so let me go ahead now when with that red herring gone let me rerun python of name. piy and hit enter and now we see too few arguments okay maybe it wants my full name let me go ahead now and run python of name. py David maen typing in both words after the name of the file and hit enter and now of course it's too many arguments fine now I'll oblige and do python of name. py and just David and there we have it my name tag printed on the screen so strictly speaking we don't have to handle exceptions if we can be a little smarter about it and just check for the things that we're worried about especially if we want to give the user more refined advice we don't want to just tell them no something went wrong or we don't want to pass we want to tell them no that's too few or no that's too many we have conditionals in our vocabulary already via which we can now Express that well let me pause here and see if there's any questions now on how we handled the error before with the index error or how now we're just proactively avoiding all index errors Al together by just checking first first is it too few is it tooo many or is it exactly what we want hi thank you um so I was wondering you you touched upon kind of using your full name um could we could we then um is there a way going forwards that perhaps we uh have people that want their full names and want their just their first name that we separate that into like oh this person has full name this person has just the one name absolutely and allow me to is uh allow me to propose we come back to that support for multiple names um but indeed we could do that and I should note too though we can support full names right now if I do this instead of typing in David space mailin which is problematic because again by definition of how argv Works each word ends up in a specific location in the list but if I add quotes single quotes or double quotes at the command line now python will view this as two total things the name of the file and this full name name and now when I hit enter I don't see the quotes the whole thing is passed in as my full name and if I want to adapt this further for multiple people we'll be able to do that as well other questions now on this version with if L if else or on accept before hi I want to I want to ask you uh can we use multiple else statements can you use multiple El's statements no else is the last catchall statement that you can have you can have multiple L if statements in the middle but not multiple elses all right all right well let's turn our attention back now to this code and see if we can't refine it a bit more by adding in some additional functionality that we get with modules like the CIS module one of the things I don't love about this version of the code even though arguably it is now correct is that the essence of my program which is just to print out the name tag is kind of relegated to this else clause and that's fine logically it's correct but generally speaking there's something nice about keeping all of your error handling separate from the code that you really care about having all of these ifs L ifs perhaps at the top of your code that are checking to make sure that all of the data is as expected but then it would be nice if only for design sake not to sort of hide in this El statement the actual code that you care about I would prefer for instance to do something logically like this I could check for errors up top and then down here print the name tags it would be nice if those are sort of distinct blocks of code all of which are here left aligned but there's a problem with what I've just done here logically what bug did I just introduce by getting rid of the Els and introducing line 10 on its own with no indentation outside of the conditional what bug have I just introduced what mistake to be clear um name error ironically it's a name error but not a name error exception it's an error with my name but I think you're Frozen for me it's going to raise an exception because even though I'm checking the length of cis.org V up top and even though I'm checking it again for being greater than two not just less than two but greater I'm still then blindly and incorrectly assuming it's now going to exist so just to be clear if I run python of name. and I don't type any arguments I've got too few I think I'm going to see that I have have too few but I'm also going to see that same exception at the very top of my terminal Windows output there's my error message to few arguments but again on line 10 I blindly proceed to still index into my list at location one which does not exist so it turns out there's a better way to handle errors like this especially if you're writing a program in Python that's just meant to run briefly and then exit anyway but maybe we could start to exit prematurely if the program itself just can't proceed if the user has not given us the data we want perhaps we should just exit the program earlier than we might otherwise so let me go ahead and do this let me go ahead and remove my comments so as to focus only on the code here and let me propose that instead of just printing quote unquote twoo few arguments I'm going to use one other function that comes with the CIS module I'm going to go ahead and call cy. exit and as the name suggests it's going to do exactly that with the system's help it's going to exit my program then and there on line 4 why is that okay well if you gave me too few arguments I have nothing more to say to you the user I might as well exit a bit prematurely and I can do this as well on line six let's go ahead and not just print that but sis. exit quote unquote too many arguments print out that message and just exit right there now I can trust that by the time I get to line eight every error condition has been checked for and so it's safe for me to assume that there is in fact and a item at location one in cy. argv so let me go ahead now and run this python of name. py enter too few arguments but I'm back at my prompt nothing more has happened let me run it again python of.pie David maen with no quotes enter too many arguments is now printed here finally python of name. py just David enter hello my name is David so we have then insist two forms of functionality now we have access to this variable sis. arv this argument Vector that gives me all of the words that were typed at the prompt including the program's own file name and it turns out if we read further in the documentation there's an exit function that can take different types of inputs but if I pass it a string like this it will indeed print that string for me and then exit from my program then and there questions now on exiting from programs like this to be clear all of this time once python gets to the bottom of your file it's going exit anyway so I'm using cy. exit now just to make sure that I exit earlier than otherwise um my question is about the cis.org arv so is that capable of accepting or taking multiple elements at once let's say for example uh python name thatp David Malon I'm a male uh 20 years old and if let's say I only want to access your name which is at the first index and then your your your age is pro say at the sixth index can I say sis. RV one and another one for six to access what I just want is that possible for CIS RB uh short answer yes I think if I understand your question correctly whereby you're proposing to have many words at the end of the command and you want to access those individual words absolutely at some point it gets a little fragile I would say if you're typing so many words at the prompt that the order really matters and so it turns out there's a lot of programs and there's functionality in Python that can allow you to provide those values like name or age or any number of other fields in any order you want but pass in a bit more information textually that tells the program how you want to use it so in short what you're describing is possible and let me do a small incarnation of it as follows let me propose that we go back to my code here and let's propose that we actually now want to support multiple values at the prompt so there's going to be no such thing as too many arguments suppose that I want to generate name tags not just for David but for David for Carter for Rong Shin for others in the group who all want their name tags as well so I'm going to go ahead and do this I'm going to get rid of my L if condition because I don't want to limit the maximum number of words that are typed at the prompt anymore I instead want to iterate over every name at the prompt so I'm going to say this for Argin sis. argv go ahead and print out this time ARG so what am I doing here well even though the syntax is a little different the idea is the same as before when we've had Loops I'm using a for Loop to iterate over a list the list in question here is cy. argv ARG is a variable that I'm creating on the Fly the for Loop is going to make sure that the first time through this Loop AR is set to the first word on the command line the second time through the loop Python's going to make sure that ARG is now set to the second thing on the command line and so forth that's just how a for Loop works it updates the variable for us I don't have to call it ARG I could call it name so long as I change it to name in both places but ARG is reasonable if I'm iterating over arguments more generally if I now run this program though unfortunately there's a little bit of a bug even if I type in David and Carter and wrong Shin I'm not going to get just just three name tags in your mind does anyone see the bug I'm about to trip over it's not a huge deal if I've got enough name tags to go around but I'm going to be wasting one because this is going to print not three but four name tags whereby the first contains the name of the program itself maybe not a big deal maybe that's the sticker we don't bother handing out but it's wasteful and it it does look wrong so how could we get access to not all four elements of argv but just a a slice of Arvy and this is actually a technical term in Python and some other languages to take a slice of a list means to take a subset of it maybe from the beginning maybe the middle maybe the end but a slice is a subset of a data structure like a list well how do I actually do this in code well in Python it's actually very easy to take a slice of a list that is a subset thereof you can simply do this at the end of the list name cy. Arvy in this case you can use square brackets and then in those square brackets you can specify the start and the end of the list that you want to retain I want to start at element one not zero I want to start at element one and I want to just go to the end so I'm actually going to Omit a second number altogether it's not necessary to have a second number but I do need that colon because this is going to give me a slice of the list it's going to give me a slice of the list that starts at location one not zero and the colon and then a blank just means it's going to give me everything else so this is equivalently going to slice off the first element of the list and give me a new list that contains just those three human names not the name of the file itself let me try running this again I'm going to run python of name. py David Carter wrong Shin this time hopefully I'm going to get three and only three name tags hitting enter and indeed I've done now just this so again using some relatively simple syntax in Python we can use square brackets not just to go to specific elements like bracket zero or or bracket one we can also get subsets of the list slices of the list by doing bracket something colon Something where each of those somethings is a number the beginning or the end and they're optional depending on whether you want all of them or just some any questions now on this version which adds the loop and these slices with that new syntax can we slice starting from the end of the argument argument Vector you can you can slice something from the end of the argument vector and this might uh this might blow one's mind a little bit let me go ahead and do this uh let's see let me go ahead and do negative one at the end using a negative number here and running the same command we've just uninvited wrong Shin from receiving a name tag here so if you use a negative number it has the effect of counting to the uh in the other direction from the end of the list a good question there other questions now on slices on looping over cis.org V hi uh so I remember very early on uh when we were talking about uh only having two decimal places in uh in an um float value um does this is is that in the same vein like um because we use the the colon 2f uh so that's is that the same thing then uh why would the F be included then in the point 2f as opposed to here when you just have the numbers a really good question and it's just the short answer is that context matters so there's only so many keyo keys on our keyboard and so we sometimes use the same symbols for different things so what you're alluding to is the format code in in F string for actually formatting a number using a colon using a period using a number using the letter F and so forth and that is very specific to the F string feature of python this case has nothing to do with any of that syntax per se this is just using a colon in a different context to solve this problem to implement a slice the authors of python could have chosen another symbol but honestly looking down at my keyboard here we don't have that many to choose from that are easy to type so sometimes they have different meanings a good question as well allow me to propose now that we take things further and move away from using only those modules those libraries that python comes with to talk about more generally packages that exist one of the reasons that python is so popular and Powerful these days is that there's a lot of third-party libraries out there as well otherwise known as packages strictly speaking python itself has a term of art called a package which is a module essentially that's implemented in a folder not just a file but a folder but more generally a package is a third-party library that you that I can install on our own Mac or PC or our Cloud Server and gain access to even more functionality that other people have implemented for us now one of the locations you can get all of these packages is called the pii uh website the python package index which lives at this URL here and this is a website that is searchable via the command line as well as via the web that allows you to download and install all sorts of packages even cs50 has some of its own packages um in services like these now there's a fun one out there that's a throwback to a command that's been around for years in command line environments called cow c is a package in Python that allows you to have a cow say something on your screen if curious to read up on it its own documentation is on p.org specifically at this URL here but how do you actually get the package into your system well technically you could figure out how to download the file and maybe unzip it and put it into the right location on your Mac or PC but nowadays a lot of languages python among them has what's called its own package manager this one here called pip which is just one so pip is a program that generally comes with python itself nowadays that allows you to install packages onto your own Macs or PCS or Cloud environment by just running a command and then voila you have access to a whole new library in Python that didn't come with python itself but now it's available on your system for you let's go back to vs code here and in my terminal window I'm going to go ahead and type pip install cow now what's going on here pip is the command the package manager and I want to install what package the package called cow I'm going to go ahead and hit enter here and after a little bit of output it has successfully installed C now what does that mean that means I can now go about importing this into my own code well let's go ahead and see what this means let me go ahead and create a new file with code called say dopy because I want something to be said on the screen and in my new tab here I'm going to go ahead and import C which presumably is now installed I'm now going to import CIS as well because I'd like to use some command line arguments in this program just so that I can run it quickly and without using the input function I can get the user's name immediately from The Prompt and let me go ahead and do this I'm going to do a bit of error checking proactively this time and rather than use less than or greater than I'm this time going to say if the length of cis.org V does uh does equal two so if the human is provided just the name of the program and their own first name we're good to go I'm going to do the following I'm going to call a function called cow in the package called coway and I'm going to pass in a string hello comma and then as in the past I'm going to pass in just one string because according to its documentation it's not like print I can't pass in comma this comma that I can only pass in one string so I'm going to concatenate the contents of sis. argv bracket1 so long as then I type in my name David after the name of this program it should end up in cy. arv1 one in which case this line five of code should concatenate hello with my name with a space in between and apparently a cow is going to say it so let's see what happens here let me go ahead and clear my screen and increase the size of my terminal window let me go ahead and run python of say. py and type my name David and enter there is the program called coway it literally has a cow say something on the screen and this is a throwback to a program from yester year that tended to come with a lot of syst sys um this is otherwise known as asky art it's a textual way using just keys on your keyboard to print pictures of sorts on the screen now we can really go down the rabbit hole here and there's questionable academic value of doing so so I'll do so just once turns out the coway package comes with other functions as well one of those functions for instance is T-Rex and if I now increase the size of my terminal window we'll perhaps see where we're going with this let me now run again python of.pi this time let me not provide my name just to see if it's broken it's still okay because we have that if condition if the length of cy. RGV equals equals two and only if it equals equals 2 do we do anything that's why we're not seeing anything here let me go ahead and cooperate now say. piy space David and it's no longer a cow but if I zoom out on my screen a T-Rex why just because these are the things you can do once you know how to program you can even package them up and make them freely available to others as open source software for us it's demonstrative of a feature more generally here namely being able to install these thirdparty packages and how you might do so in Python now I'll leave this up on the screen for a moment and see if there's any questions about cows or Tyrannosaurus Rexes or packages more generally I'm really qualified to speak to just one of those hi um I've got two questions it's a bit earlier than what it's supposed to be um so the first question is the the packages that you calling um U to uh use in the program are they the same as um let's say because I'm doing Java um the same as calling a class of a Java file in order to use its functions and my second question is what's the actual purpose of using command arguments as you used because it's not really the best way to uh as you say be user friendly where as in let's say the person who's using the program doesn't know what it what they want what the the program's asking them really good questions the first question about the comparison with Java python packages are similar to Java packages where you have something do something do something at the top of your program that gives you access to a class or something else python itself supports classes more on those down the road and you can do very similar things in python as you can do with Java but the analog really is python packages to Java packages here as for command line arguments you ask a good question why do we use them especially if they're a little less user friendly they're a little less user friendly to people who aren't in this Zoom to be honest you and I as we learn more and more about programming and more about command line arguments I dare say will become more comfortable with and tend to prefer the ability to customize commands using these commandline arguments why productivity it tends to make you faster because you get into the habit of knowing exactly how you can configure your software without having to manually answer questions and case in point all of this time uh have we been running python of something. py you could imagine not doing that you could imagine typing only python hitting enter and then you're prompted for the name of the file you want to run so you type in something piie and then it runs not a big deal but I I would argue that over time you're going to get a little tired of that tedium and you would much prefer to just automate the command again and again and again especially with little conveniences like being able to hit up and down in your keyboard history so as to rerun those same commands automation is Big too if you emerge from a class like this and start using python to automate processes at work or for personal projects or the like the ability to specify all of your inputs on the one line just means you can get work done more quickly so so hands down absolutely using commandline arguments is a more Arcane uh feature of systems that most of us are no longer as familiar with because of Windows and Mac OS and other operating systems that have buttons and goys and menus but the more comfortable get you get with programming I dare say the more you will tend to prefer these capabilities because they allow you to do things more quickly with that said allow me to propose that we take a turn toward yet another package that's particularly popular and just as easy to install all toward an end of using apis now apis are not something that's python specific more generally an API is an application programming interface and it can refer to python files and functions but often apis really refer to third-party services that you and I can write code that talk to many apis but not all live on the internet these days so that so long as you have a browser or so long as you have some experience with Python Programming or programming in any language you can write code that in effect pretends to be a browser connects to that thirdparty API on a server and download some data that you can then incorporate into your own program now how do you do this well python has a very popular package that you can install via pip called requests the requests Library allows you to make web requests internet requests using python code essentially as though you were a browser yourself you can automate therefore the retrieval of URLs that start with HTTP or https the documentation for this library is at a URL like this but it too can be installed at the command line and even though it's third party it's one of the most popular and commonly used packages out there in Python and this too is one of the reasons again that python is so popular there's just so many solutions to problems that you and I have or are invariably going to have when we write projects of our own there's just a really vibrant EOS system a really Vibrant Community of Open Source software that's that easy for us to install let me go back to my terminal window now and run pip install requests in order to install this package on my own system and after some lines of output I'll see that it's successfully installed now let's go ahead and create a new file here for instance itunes. it turns out that Apple has its own API for their iTunes service the software that provides you with the ability to download and search for music and songs and other information as well and it turns out that let me go back over to my computer here and open up a browser like Chrome and let me go ahead and visit this URL here https col itunes.com search question mark entity equals song Ampersand limit equals 1 Ampersand term equals Weezer now I constructed this URL manually by reading the documentation for Apple's API application programming interface for iTunes and what they told me is that if I want to search for information about songs in their database I should specify entity equals song so that it's songs and not albums or artists or something like that if I just want to get back information on one song I'm going to provide limit equals one and if the band I want to search for the artist is Weezer I should specify term equals Weezer so with this if I go ahead and hit enter and visit this URL I actually end up with a text file in my downloads folder on my Mac if I go ahead and open that text file that my browser just downloaded we'll see all of this text here which at first glance might look a c bit cryptic but it actually follows a pattern notice this curly brace at the start and notice this closed curly brace at the end notice this open square bracket here and notice this closed square bracket here and in between those pieces of syntax are a whole bunch of strings and values in fact a whole bunch of key value pairs what we're looking at here is a standard text format known as Json JavaScript object notation which yes is technically related to yet another programming language called JavaScript but Json itself is typ typically used nowadays as a language agnostic format for exchanging data between computers by language agnostic I mean you don't have to use JavaScript you can use python or any other language to read Json or write it as well and it's a completely text-based format which means that if I visit that URL with my browser what gets downloaded is just a bunch of text but that text is formatted in a standard way using curly braces and square brackets using quotes and some colons that ultimately contain contains all of the information in Apple's database on Weezer song at least the first one CU I limited it to one in their database and that's an API an application programming interface a mechanism whereby I can access data on someone else's server and somehow integrate it into my own program now of course my browser Chrome is not something I wrote I should actually write some python code that perhaps pretends to be a browser to grab the same data so let's do that let me go back to vs code here and let me write a program with code itunes. and we're going to write some code via which I can then use the iTunes API and in turn python to get information about any band that I might want I'm going to go here and import first the requests Library which I installed earlier in order to make those HTTP requests I'm going to go ahead and import the CIS Library via which I'll have the ability to use command line arguments like specification of the band that I want to search for if not Weezer and then down here I'm going to go ahead and insert some error checking to say if the length of cy. argv does not equal to so if the user does not provide me with the name of the file they want to run and the name of a band and that's it you know what let's just go ahead and exit for now I could provide a more explanatory message but for now I'm going to keep things simple and just exit the program prematurely so that I can trust Hereafter that cy. arv has what I want and now I have the opportunity to use the requests library to write some python code that effectively is pretending to be a web browser so as to connect to that same https URL on Apple's own server so now that I've guaranteed that the user has typed in not just the name of the file but also the name of a band at the prompt giving me a length of two for cis.org V let's go ahead and execute requests.get which is a function inside of the requests package that will literally get some response from a server and the URL that I want to get is the exactly the same as before https itunes.com search question mark entity equals song Ampersand limit equals 1 Ampersand term equals previously Weezer but let's make this program a little interactive and actually allow the human to specify at the command line what artists they'd like to search for so I'm going to go ahead and close my quote early and just append using the concatenation operator as in the past sis. Arvy bracket1 and now it'd actually be nice to store the response from the server in a variable so I'm going to go ahead and say response equals and to store all of the response that comes back from the server in a variable called response down here now I'd like to just understand what the server is returning to me to make sure I know how next to proceed so this isn't going to be very pretty yet but I'm going to go ahead and print out response. Json which ensures that the data I'm getting back is formatted on my screen as is exactly that Json the same text format as we saw on my screen it's not a useful program yet I'm really just learning along the way but let me go ahead now and increase the size of my terminal window and run python of itunes. and type in the name of a band like Weezer and hit enter and what we see on the screen formatted almost the same as before is exactly that same text but what you'll see here is that this has been standardized now as a python dictionary what indeed Apple's returning is technically adjacent response JavaScript object notation but python the request library is converting it to a python dictionary which happens to use wonderfully coincidentally almost the same syntax it uses curly braces to represent the dictionary here and a closed curly brace to represent the end of it here for any lists therein it uses a square bracket here and a closed square bracket down here it uses quotes single quotes in this case or equivalently double quotes to represent the keys in that dictionary and after a colon it stores the value of that key and so you'll see that indeed we have a result count key whose value is one but then a more interesting result key called results whose value is this entire list of data now honestly this is such a big blob of text that it's going to take me forever to wrap my mind around what I'm seeing so let me propose temporarily we use another library in Python that will allow me to format my data a little little more cleanly it turns out that python also comes with a special Library uh called Json that allows you to manipulate Json data and even just printy print it that is format it in a way that's going to be way easier for you and I to understand so let me go back to my code here let me shrink my terminal window and let me propose that just temporarily again we do this let me import this additional Library Json which comes with python so I don't need to install it manually with Pip and let me go ahead now and not just print out response. Json which was that Big Blob of hard to understand text let me go ahead and use one other function here called json. dumps for dump string and pass to that function that response. Json return value so again I'm just introducing another function who I claim it has a purpose in life of pretty printing nicely formatting on the screen the exact same information and I know this from the documentation having done this before but I'd like things to be nicely into Ed and according to the documentation if I pass in a named parameter of indent equals 2 that's going to indent everything at least two spaces I could do four or something else but it's going to be enough to help me wrap my mind around what the data is I'm getting back because again I'm just learning along with you so let me increase the size of my terminal window again let me run python of itunes. and again let's search for Weezer and hit enter and now notice it's still a little bit cryptic because there's a lot going on here but my gosh I can totally read this more easily now notice now that I still see the first curly brace which means hey this is a dictionary in Python a collection of keys and values the first key is called result count it happens to be displayed in double quotes now but that's just an issue of formatting it could be double or single so long as we're consistent the value of that key is one why well I told the URL to only limit the responses to one Weezer song so I've gotten a result set of one if I increase that limit I could probably get more then the interesting part of this response is really the data itself notice in the res results key here there's a really big value the value is a python list as implied by this square bracket what does this list contain well I know from skimming it earlier that this contains one dictionary and that's why we see another curly brace here so again if this gets a little more complicated keep in mind that a dictionary is just a collection of key value Pairs and python uses curly braces to indicate as much it is perfectly reasonable for a dictionary to be inside of another dictionary if the value of some key itself is another dictionary so this is a common Paradigm and even though it might seem a bit cryptic it's just something that allows us to associate more keys with more values now most of this information I probably don't care about for instance according to Apple the unique identifier for Weezer is apparently 115,000 234 that might be useful if I'm making my own database and I want this to be searchable but for today's purposes all I care about is the name of the track otherwise called track name as key and the first song and only song because we limited it to one that we got back from iTunes here is the song that you might know by Weezer called Say It Ain't So so now I have a bit of a clue if my goal here is to implement a program called itunes. that doesn't just dump the response from the which is admittedly very cryptic but to print out all of the songs that iTunes has for the band called Weezer maybe I can iterate over this somehow so let me backtrack here's the key called track name it is inside of a dictionary that is the value of results here so how can I go about getting this well let me go ahead and try this let me go ahead and Shrink my terminal window back down and let me propose now for one final flourish we don't just lazily print out the contents of that response because that's not interesting or pretty for anyone let's do this let me go ahead and create a new variable just for the sake of discussion called o for object and I'm going to go ahead and call uh o equals response. Json just to store that Json response specifically in a variable called o but I could name it anything I want and now I'm going to do this for each result in that object's key called result go ahead and print out that results track name and notice I have used exactly the same capitalization track name has a capital N results is all lowercase and let me rewind before we run the actual program in line eight we are making an HTTP request using python to the server just like you and I as humans type URLs into a browser and hit enter this is the python equivalent there of I am then on line 10 just grabbing from that variable that contains the server's respon the Json object that I care about the thing between those curly braces at the very top and the bottom but because we've poked around and because I read the documentation earlier I know that that object has a key called results and that results key again is a list now at the moment that list contains only one song Say It Ain't So because I limited my response to one but even so my Loop will work it's just going to iterate once and each time through that loop it's going to print the current results track name if I want to make this even more interesting let me change this limit now from one to 50 so I'll at least get back 50 track names instead let me go ahead now and increase the size of my terminal once more and go ahead now and run python of itunes. searching again for a band like Weezer and here we go and voila there are 50 songs that iTunes has for Weezer and if we scroll back up to the top here we'll see that the very first one there is indeed say it ain't so but now we got undone The Sweater Song Buddy Holly apparently another rendition of Say It Ain't So perhaps from another album another Buddy Holly undone my name is Jonas and so forth questions now on this program which integrates python with a real world third party API yeah hi uh can we use breake instead of system. exit exit good question but no um break again is used to break out of things like Loops like we saw ear clear cy. exit is used to break out of the whole program itself use break for Loops for now and use cy. exit to terminate the whole program good question other questions now on this program are others from where we bring the name of the key results from where do we get the name of the key uh results itself yeah can we change the results name you cannot so we could in our program so the keys that come back in that Json response to be clear come from itunes. apple.com some engineer some team of Engineers decided for us what all of those keys would be called including track name results result count and everything else you and I can absolutely store those same values in variables just like I'm doing here with o just like I'm doing here with result you can rename those keys anything you want using python variables but the Json response is coming from that thirdparty server other questions yes sir sir uh I have a question related to to C package so like uh yes so sir what sort of ask Graphics is it capable of outputting the coway package um I would refer you to the URL in the slides earlier uh if only because it's more thorough they have not just cows but Tyrannosaurus Rexes and several other animals as well I should emphasize that this is not a package I suspect you will use much in the real world it's really just meant to be representative of the types of packages you can install but allow me to refer to the documentation for what more is there but aski artart uh is the all we had before there were emojis let alone gifs and jpegs and pings but it's what's is immortalized in C well allow me to transition us back now to one final capability of python which is that you yourselves have the ability to make your own libraries up until now we've been writing all of our functions in our one file hello pi and everything since and now that we've introduced modules in Python like random and statistics we can import those that come with python but that's other people's code as well and we've now used Pip this package manager to install third- party packages as well in the system and using other people's code still but to come full circle what if you yourself find yourself implementing the same kinds of functions again and again or you find yourself opening up old programs copying and pasting code you wrote into new programs because you have the same problem yet again a good practice would be to somehow bundle up that code you keep reusing and make your own python module or package you can keep it local on your own Mac or PC or Cloud Server or you can go through the steps of actually bundling it up making it free and open source and putting it on something like pii for others to use as well okay I'm going to go ahead and run code of sayings. py to create a brand new file called sayings dopy which is going to be my own sayings module and I'm going to define a couple of simple functions in there I'm going to define a hello function that's going to take name parameter is input and that function is simply going to print out an F string that contains hello comma and then in curly BRAC whatever that person's name actually is then I'm going to go ahead and Define one other function a goodbye function that has def goodby also takes a name as its input and then that prints out by contrast an F string that says goodbye comma and then in curly brace's name and now just for good measure just so I can be sure that these functions are working as expected I'm going to go ahead and Define a main function in here too just for the purposes of testing and I'm going to go ahead and Define a main function that simply does a couple of tests for instance it calls uh hello of quote unquote worlds shall we say and then it's going to call goodbye of quote unquote world as well and hopefully what I'll see on the screen then is hello world and goodbye world when I run this program of course as always I need to explicitly tell python to call that function so I'm going to call Main at the very bottom of this file all right all right let's try it out python of sayings. py enter and indeed I see Hello World and goodbye world and so I think it's reasonable for me to assume that these functions albeit simple are pretty correct at this point but now suppose that I want to use these functions as though I've indeed created my own Library my own python module that makes available a hello function for me or anyone else who wants to use it or a goodbye function as well well let me go ahead and open up again say. py but start fresh and rather than have the C say anything let me go ahead and have my own Library do the talking so I'm going to go ahead and as before import CIS so that I have access to command line arguments and from my own module called sayings I'm going to import hello so because I created a file called sayings. py I can say from sayings and it's inferred by python that I mean sayings. py at least in this current directory but I specifically going to import just one of the functions for now namely hello and now I can do something like this if the user obliges by giving me two command line arguments which I can check by just checking the length of cy. argv I'm going to then go ahead and call this new hello function passing as its input assist. arv bracket one which should hopefully be the person's name which I'm going to expect them to type at the prompt so here we go I'm going to go down to my terminal window run python of s.p and my own name because I want my own name to end up in the command line arguments and therefore be part of the hello so when I hit enter and just a moment I should hopefully see hello comma David so here we go enter and huh I see Hello World Goodbye World and then I see hello David so why is this happening well it turns out even though I've done everything according to our own past practice it's not really the right way to go about calling Maine after all if I'm blindly calling Maine here at the bottom of my file that means whenever this file is loaded by python Maine is going to get called and unfortunately that's true even if I'm importing this file or just a function from this file as I am here in my s.p program this is to say on line three here when I say from sayings import hello this effectively tells python to go find that module sayings. py read it from top to bottom left to right and then import specifically the hello function unfortunately by the time python has read the file from top to bottom left to right that last line of code recall is to call Maine Maine gets called no matter what so really the right way to go about using a main function which does solve that problem of ensuring that we can order our functions however we want and all the functions will be defined at the time they're invoked I shouldn't be unconditionally calling main at the bottom of this or really any of my programs I should instead use this technique I should say if underscore underscore name underscore underscore equals equals quote unquote underscore uncore maincore uncore close quote then and only then should you actually call Main well it turns out that this variable is a special symbol in Python underscore uncore name underscore underscore and notice that vs code because of its font isn't quite showing those two underscores but they're indeed there to the left and the right this is a special variable whose value is automatically set by python to be quote unquote main when you run a file from the command line as by running python of sayings. piy so Watch What Happens now with this additional conditional in sayings. py if I run python of sayings. py it still works as before because name will be automatically set to underscore uncore maincore uncore when I run this file using python ofs sayings. py but notice this name is not going to be set to quote unquote main it's going to be set to something else technically the name of the module when I instead import the file like I do here so this highlighted of code even though it will cause python to go find sayings. py read it from top to bottom left to right it's going to ignore the call to main this time because it's wrapped in that conditional in this case when I'm importing a file and not running it directly at the command line Maine will not get called by definition of name's value so let me go ahead and try this instead of running python of sayings. py which is the module which contains that conditional main let me go ahead here and run python of say. py which is the program here before me that Imports hello from sayings but because of that conditional it's not going to say hello to anyone else except me in this case all right we're here at the end of our week it's only appropriate I think to import something other than hello why don't I go ahead and import not hello but goodbye from here let me go ahead and call goodbye instead of hello and this time when I run python of sayy I'm not going to type my own name allow me if I may to type in the whole world so that our final sentiment today is goodbye World indeed that's it for this week we will see you next time [Music] [Music] all right this is cs50's Introduction to programming with python my name is David men and this is our week on unit tests up until now we've been writing a lot of code and you might have been testing your code by running your program and passing in some sample inputs and running it again and passing in some sample inputs or you might have been waiting for us to test your code instead but it's actually much better practice to get into the Habit sooner rather than later of testing your own code using Code of your own in fact whether you're writing a personal project or working in industry it's very common nowadays to not only write code to solve the problems that you want to solve but also to write a little extra code to test the code that you wrote and that's what we're going to focus on today writing our own test so as to be all the more confident all the more certain that the problems we have been trying to solve are in fact solved correctly so let's rewind a few weeks now to a program we wrote a while back namely to to calculate uh numbers and specifically we left off with this calculator on trying to compute the power of a number like X squar or uh where X might be two or three or some other number as well well let me go ahead and resurrect that file by going into my terminal window here and running again code of calculator. Pi and let me go ahead and pick up where we left off way back when by defining a main function here and then in my main function I did something like this I said x equals int of input and I asked the user what's X question mark and then I immediately went ahead and printed out something like x^2 is and then I passed in as a second argument to print the result of calling a function called Square passing in that value X now of course I haven't yet implemented the square function so let's define that as well let me go down a couple of lines and Define square and it takes an argument recall a parameter that at the time I called n for number so I'll do that again though I could technically choose any name for this variable and I call did this I returned n * n and there were multiple ways to do this the squaring a number is multiplying it by itself so I could also use other syntax here but this is what we ultimately settled on and then recall that I ultimately called Main in order to kick off the process of running this program so just as a test manually let me go ahead and run python of calculator. piy and hit enter what's X let's start with two all right x^2 is 4 I think that's correct so let's run it again just for good measure of calculator. Pi let's type in three for X this time x^2 is 9 and I think that's correct and I might be feeling pretty good at this point and I go off and submit my code to a course or I post it on the internet for others to use but I haven't really methodically tested this code and it's not necessarily the case that it works entirely in fact I haven't really considered a number of corner cases I went with some pretty obvious numbers like two and three but what about zero what about negative numbers what about any number of other infinite numbers well we're not going to test infinite number of inputs to this because the program would never halt but we should test some representative inputs ultimately but before we do that let's get into the habit of making sure that Maine isn't always called let's adopt this habit again of doing if underscore uncore name underscore underscore equals equals quote unquote underscore uncore maincore underscore only then should we execute Main and I'm doing this now proactively because I want to make sure that when I import my Square function perhaps from another library from another file treating it as though it's a library I want to make sure that main is not just automatically called itself now what do I want to do from here now that I've modified this program as follows well let's go ahead and write a completely different program whose sole purpose in life is to now test this program so I've got my actual calculator in calculator. I've readed myself to call Main conditionally so that I can safely import one or more things from this file in another file well what should that other file be well by convention I'm going to create a file that's called test underscore and then because the thing I'm testing is this calculator itself let's call this file test calculator. piy that's going to give me a new tab in which I can write a brand new program whose purpose in life is now specifically to test that program but really that program's specific functionality built into that program is the square function let's focus on testing that function all right so how do I access that function in this program well recall that I can import a function from another file as though it's a library of my own a so-called module so I'm going to do this from calculator import Square I could go ahead and just import Square itself but then I would have to prefix my use of square recall by saying calculator dot everywhere and it's just a little cleaner to just import the one function and now let me go ahead and do this let me go ahead and Define a function called test Square this two is a convention if you want to test a function called Square your function for testing should be called testore Square or alternatively you could do Square underscore test but I'll adopt this convention here now what kind of tests can we do well I don't dislike the test I ran earlier testing xals 2 and x equals 3 but every time I uh want to test my program previously I would have to do that manually and that's going to get tedious it's not going to be easy for someone else to test it and if I'm actually working in the real world it would be nice if I could automatically have my program tested again and again by having some automated process run my own code so let's do that and take the human ultimately out of the equation so how might I go about testing the square function that I've now imported per line one well in my test Square function why don't I do this if uh the result of calling square of two does not equal four why don't we go ahead and print an error message because I know that in the real world 2 squared should equal four so if square of two does not equal four there's a bug in my program there's a bug in my function I've made a mistake so let me go ahead and print something like that so I or someone else knows 2^2 was not four for instance so I could print out anything here what should I maybe next test well let's do more than one test let's say if the square of three does not equal 3^2 9 then let's go ahead and print out that 3^ SAR was not 9 so I haven't done any more testing than I did earlier but I've baked those two tests xal 2 and xal 3 into my own code here so I can now run those tests automatically if you will now it's not enough to just Define a function called test Square I actually if I want to run this function need to call it somehow and our convention for doing that is the same as always in this function here in this file two let me Define Main and Main's sole purpose in life is going to be to test square and now at the bottom of this file as before let me go ahead and adopt my Convention of if underscore uncore name underscore uncore equals equals quote unquote underscore uncore maincore uncore then go ahead and call Main so a lot of this is just boilerplate like we've seen this before defining a main function and calling a function to kick off some process now adding the conditional at the bottom of the file to make sure I'm only conditionally calling main just in case I import anything from this file elsewhere so let's see let's go ahead and test my code now let me go ahead and run test calculator with python and hit enter and nothing outputs nothing outputs but I think it's okay I think no output is good because look at my test Square function I'm not printing anything if all seems well so let's let's demonstrate as much by going back to my calculator and let me break it let me introduce a bug maybe I didn't even get it right the first time maybe my code originally looked like this I wasn't thinking I forgot my squares and so I thought that the square of a number is n plus n instead of n * n so a reasonable mistake to make perhaps arithmetically let me now go back to my test calculator which which I'm not going to change but I am going to rerun it python of test calculator. Pi going to cross my fingers here but for not I'm going to see immediately that 3^ SAR was not n now what is it well let's see when your tests fail how can we put our finger on what's wrong well it's a little interesting that I completely broke my Square function and yet only one of these tests is failing it looks like this test lines 9 and 10 is fine because I'm not seeing that output but of course these two lines this test is failing because 3^ s is not n when I'm using plus so just to be clear here why is my function only partially broken just to be clear why am I seeing only one error instead of two even though the square function is now mathematically broken because 2 plus two is four no yeah I mean it's as simple as that I just got lucky that 2+ 2 is the same thing as 2 * 2 so this is one of those Corner cases and this is why it's good to be in the habit of not just testing one thing but test several and make sure you're covering your bases so to speak so I got lucky here and that explains why I'm seeing only one error even though the function itself is flawed but let me propose that there's another way we could do this because honestly if I extrapolate from this simple example running not just two tests but three or four or 10 or 20 tests you can imagine that my God the code is going to get so much more complicated than the function itself I mean already look in calculator. the function in question is two lines long and yet in test calculator the fun code in question is five lines long like I've written more code to test my code than I actually wrote original code so the fewer lines of code we can write when testing code I think the more likely you and I are to do it because it's going to be literally a little less work and just fewer opportunities for mistakes so what's another approach I can take here well it turns out in Python there is another keyword that we haven't yet used which is this here assert assert is a keyword in Python and some other languages as well that allow you to do exactly that as in English to assert that something is true to sort of boldly claim that something is true and if it is nothing's going to happen no errors are going to appear on the screen but if you assert something in Python and it is not true that is the thing you're insert asserting a Boolean expression is false you're actually going to see some kind of error on the screen so let's go ahead and try this new keyword as follows let me go back to my code here and just to make it a little simpler let me propose that I I use this new keyword as follows let me simply assert that the square of two should equal four so I've changed my logic instead of checking for not equals I'm now asserting very loudly that it should equal four and then on one additional line let me do the other test assert that the square of 3 equals equals 9 and that's it no if no indented print I'm just going to assert more simply these two things that I want to be true well let me go ahead now with calculator. pi still broken I'm still using plus accidentally instead of multiplication let me go ahead now and run python of test calculator. Pi crossing my fingers as always but it's not going to go well this time a whole lot of Errors seem to appear on the screen and if I scroll up here for this traceback we'll see that the thing that failed was this line here assert Square of three equals equals 9 now unfortunately when you're using the assert keyword it's not terribly userfriendly it shows you the files and the line numbers involved but it does show you the specific line of code that failed the assertion that failed so to speak it's now kind of up to you and me to infer from this well wait a minute why is the square of three not equal to 9 so it's not super user friendly but honestly it was like half as much code for me to write it's just two lines instead of those previous four but notice this little Remnant down here this was an assertion error and we have seen errors before we've seen errors before when we've made other mistakes in our code and in the past what was our solution for catching those errors how do we catch errors that seem to resemble this even though we've not seen this one before um try and accept yeah in Python we can use the try and accept keywords to try to do something optimistically except if something goes wrong do something else instead so this is a step forward and that I can at least catch this error but it's going to be perhaps a step backward and that I'm going to end up writing I'll admit in advance a little more code uh instead so let me go ahead and try this let me go back into my code here and instead of just asserting blindly let me go ahead is to proposed and try to do this first assertion except if there is an assertion error like we saw a moment ago then go ahead and print out something more userfriendly that explains what actually failed 2 squar is uh was not four and let me go ahead similarly and try to assert that the square of 3 equals 9 except if there's an assertion error there in which case I'm going to print out more user friendly 3^ squar was not n so I've taken a step forward but also a step back because now I have more code but I have at least introduced assertions and exceptions in a manner consistent with how we've seen it in the past when something goes wrong you actually see an exception raised well let me go ahead and run this version of the program now instead python of test calculator. crossing my fingers all right it still failed because I'm seeing output but we're back to at least userfriendly output so that's at least progress in some way here but it's again more code than might have been ideal and in fact if we continue this further what if we actually want to add additional test cases here as well well it seems like we might end up writing way more code than would be ideal for instance I'm testing two and three now I should probably test some negative numbers as well so why don't I go ahead and add in for instance let me go ahead and copy and paste this let me try to assert that the square of -2 equals equals 4 which should be the case mathematically and if not let me go ahead and change this to say -22 was not four and you know what let me go ahead and copy paste this again test another negative number just for good measure let's test the square ofg -3 which should equal 9 but if it doesn't let's go ahead and say that -32 was not 9 and just to think aloud here what might be another good value to test I've tried two I've tried three I've tried ne-2 I've tried negative3 I can't try in infinite numbers but there's at least something that's a little different in between those values let's try zero zero is an interesting case too just in case something might be wrong and Y zero I'm just going with instincts here right odds are positive numbers are generally going to behave the same negative numbers might generally behave the same zero might be a little anomalous there's no uh science to it necessarily but rather considering for yourself based on your own experience like what are the potential Corner cases based on the function you're trying to test I'm trying to test something mathematical so I want to test representative values so let me go ahead and paste in one more try accept block let's assert that the square of zero should equal zero and if not I'll say something explanatory like 0^ squar was not zero now if I go ahead and run this python of test calculator. piy and hit enter now I see multiple errors and and this is interesting it's a bit of a clue because notice that some but not all of these assertions are failing the one for 2^ SAR is apparently okay as we noted earlier recall that 2^ SAR happens to be 2 plus 2 so that bug doesn't really throw off our test but it's a good thing we tested for three it's a good thing we tested for neg -2 and neg3 because all of those tests caught this error the zero test did not notice because 0 squared is of course 0 but 0 + 0 is 0 so we're getting lucky or unlucky there depending on how you you view the glass is half full or half empty here we at least by way of having multiple tests caught this mistake somehow so it would be nice though if we weren't writing so much darn code here right because notice what I've done I have try except try except I have all of these assertions I have a main function I have this if conditional at the bottom of my file I mean honestly who's going to want to write 31 lines of code now just to test a two line function right no one's going to write test code like this if we're all writing so much more code to do the actual testing so people have solved this problem if you are in the habit of testing your code a lot or wanting to if I'm in the habit of wanting to test my code a lot if everyone else in the real world is in this habit of wanting to test their code why don't we create tools that make it a little easier to do so and in fact there is a mechanism for doing this whereby we can use a tool that's popularly called pest so py test is a third-party program that you can downloaded install that will automate the testing of your code so long as you write the tests but what's nice about this library and others like it is that it adopts some conventions so that you don't have to write as many lines of code yourself manually they do some of that automatically for you now this is a thirdparty library there's other libraries for unit tests uh so to speak that is testing units of your code uh some of them come with python itself we're proposing that we look at py test today because it's actually a little simpler than the unit testing Frameworks that come with python itself and what do we mean by unit testing unit testing is just a formal way of describing testing individual units of your program what are those individual units they're typically functions so unit tests are typically tests for functions that you have written now what does this mean in practice here well let me go back to my VSS code here and let me propose that we simplify my test calculator significantly I'm going to go ahead and delete all of these tests which were um which we're accumulating to like 31 lines of code and let's see if we can distill the tests to their Essence using p test from my same calculator program let me still import Square so I do still need that line of code so that I can test that specific function now I'm going to go ahead and Define a function just like I did before as follows I'm going to define a function called test Square Again by convention test underscore and the name of the function you want to test though it doesn't have to be that way and now I'm going to go ahead and make a few assertions I'm going to assert that the square of two should equal four I'm going to assert that the square of three should equal 9 I'm going to assert that the square of -2 should equal 4 and I'm going to insert that the square of -3 should equal 9 and lastly for now I'm going to assert that the square of 0 should equal zero so I'm still using the assert keyword as I introduced earlier and even though it was a little tedious to type those I mean it's only eight lines of code now and they're so easy to type it's try and accept and all of this wouldn't it be nice if something else someone else handled the try the accept the printing all of the standardization of actually running these tests and that's where indeed P test comes into play per the documentation for py test which can itself be installed with Pip install py test which we've used to install other libraries in the past you can look at the documentation here for all of its formal usage but fortunately pest is pretty userfriendly testing Frameworks go and it actually allows us to Dive Right In by just running P test on the code that we've written so if I go back to vs code here and look at my test calculator. piy which notice has no main function anymore it has no conditional it has no tries it has no accepts it has no prints it just has my few assertions Pi test and other libraries like it are going to automate the process of running these tests for me and informing me on the screen whether or not any of those tests failed so so let me go ahead and do this I'm going to go ahead and increase the size of my terminal window for a moment just so we can see more on the screen and I'm going to run not python as I've been doing I'm going to run Pi test which again is this third party tool for running tests in your code I'm going to run Pi test of testore calculator so that same file I'm going to cross my fingers as always and hit enter and we'll see that ah something has failed now admittedly even though I do think you'll find that Pi test is relatively simple to use its output at least at first glance is not necessarily super user friendly so what are we seeing here we'll notice at the very top of my window is the command that I ran after my prompt right below that is a single F in red which means fail so not very encouraging I tried really hard here but fail is my grade on this program but let's see exactly what happened well if I look at this excerpt here under failures you'll see that test square is the function that failed all right that makes sense because that's the only one I wrote and you'll see here somewhat uh Arcane output describing what the error was so what you're seeing here is the first line of output equals equals 4 which was fine there's no red error message below that so that one's okay but this line of code here assert that square of three equals equals 9 pi test did not like that assertion because it didn't end up being true in fact per the red e at the start of this line You'll see that I'm effectively trying to assert that 6 equals equals 9 now where did the six come from okay wait a minute if my test involves this notice that where 6 equals square of three this is saying that because I've called Square passing in a value of three it turns out its return value is six and of course mathematically six does not equal equal 9 so that's why this is failing now Pi test is not as user friendly as telling you exactly why the bug is there or how to fix it this is really just a clue to you what must be wrong what you're seeing here is a clue that the first test passed because there's no red error below that line of code but this test failed somehow or other your Square function is returning six when passed in three instead of nine so at this point you sort of put your detective hat on you go back to your actual code and you think about in calculator to Pi how in the world is line seven of my square function returning six instead of nine and at this point odds are the light bulb would go off above your head proverbially and you would see oh I'm using addition instead of multiplication but what P test has done for us is automate the process of at least pointing out that error for us and if I now go in and fix this let me go ahead and the light bulb has gone off I change the plus to a uh to multiply now I'm going to go ahead and after clearing my screen I'm going to run not python but Pi test of test calculator. Pi crossing my fingers again and now it's green and I see just a DOT which indicates that my one and only only test passed I'm good 100% success with my test now after fixing that bug all right let me pause here and see if there's any questions so my question is what if a user uh instead of because we are taking input from the user what if the user is uh somewhat malicious and types in a string instead of an integer or maybe he types in a float or some other data type yeah so what if the user like we've seen in past examples types in instead of a number when we're expecting an integer how do we test for something like that at the moment I'm admittedly not testing user input if I go back to my code here notice that my calculator function of course has the square function that we keep testing and retesting but notice that all of the user input is currently relegated to my main function and admittedly as of now I am not testing my main function so they could be one of those bugs and in fact there would be because if the user types in a string like cat instead of an integer like two or three then line two recall would actually raise a value error exception so we've seen that before so when it comes to testing your code this is actually a good reason for having multiple functions in your program rather than putting all of your logic in just the file itself rather than putting all of the logic in just main it's actually really good really helpful practice to break your ideas up into smaller bite-sized functions that themselves are testable and what do I mean here Square is perfectly testable why because it takes as input a parameter called n and it returns as output an integer which is going to be the square thereof hopefully it has a well-defined input and a well-defined output it is therefore completely within your control in your test program to pass in those values now I will say if you want to test whether Square behaves properly when past something like a string like quote unquote cat we could absolutely do something like this assert that the square of uh quote unquote cat it's not going to equal something you can actually using different syntax assert that a specific exception will be raised so if we were actually going to go back into our Square function improve it and deliberately raise an exception we could test for that too but for now I'm deliberately only testing the square function I'm not testing for specific user input but that's another problem to be solved other questions now on unit tests uh do use the units test to test the code for the C cs50 check so check 50 is similar in spirit cheze 50 is a tool that we cs50 wrote that is essentially doing something like pie test for the evaluation of students code it is similar in spirit but think of cze 50 as being an alternative to P test if you will but it works a little bit differently but same idea pie test and unit testing more generally is a technique that is independent of cs50 and is something that you can and should be doing on your own code both in or outside of this class how about one other question here on on um on our uh unit tests uh my question is instead of writing four times like s square of 2al 4 uh instead of that can we write if is uh I is equals to in square brackets the numbers we want instead of writing four lines a really good question absolutely right now if I go back to test calculator. it's in pretty manual I mean it took me a while to say and to type out those several lines and you could imagine writing some kind of loop to just assert in a loop that this equals that that this equals that and so forth using a list or using maybe a list or a dictionary or some structure like that so yes you can absolutely automate some of these tests by not just doing the same thing again and again you can still use all of the syntax of python to do loops but generally speaking your test should be pretty simple and in fact let me propose that we improve upon even this design further because at the moment what's not really ideal when I run all of this uh when I run all of these tests when my uh function is buggy is notice the output that I got let me reintroduce that same bug by changing my multiplication back to addition let me increase the size of my terminal window again and let me run Pi test again of test calculator. Pi so this is the version of my code now that has the bug again so I'm going to see that big massive failure where this failure has been displayed to me but this is not as helpful as it could be right because I have all of those other tests in my code recall that I had what 1 2 3 four five separate tests and it I'm only seeing the output of the first now why is that well if we go back to my code here you'll see that the first assertion that's failing namely this one here that assert of square of three equals equals 9 the other tests aren't even getting run and that's not a big deal in the sense that my code is buggy so one or more of them are probably going to fail anyway but wouldn't it be nice to know which of them are going to fail and in fact it's ideal to run as many tests all at once as possible to give you as many Clues as possible to finding your bug so let me propose that we improve the design of my testing code now still using pi test as follows instead of having one big function called test square that tests the entire function itself with so many different inputs let's break down my tests into different categories and here too there's no one right way to do this but my mind is thinking that I should maybe test positive numbers separately test negative numbers separately and test zero separately I could think of other ways I could test even numbers I could test odd numbers or maybe some other pattern alt together but separating this big test into multiple tests is probably going to yield more clues for me when something goes wrong so let me do this let me go ahead and rename this function to test positive initially and let me include in that function only those first two tests let me then create another function here called test negative and in this function let me test only -2 and -3 then down here let me do one more def of test zero and I'll just run one test in there so I have the same assertions the same five but I've now divided them up among three separate functions what's nice about Pi test and other unit testing Frameworks is that all three of these test functions will be run automatically even if one of them fails the others will be attempting that means that if one or two or three of them fail I'll have one or two or three Clues now for helping me find that mistake so let me go ahead and again increase the size of my terminal window just so we can see more on the screen my calculator still has the bug using addition instead of multiplication let me go ahead and run not python but again Pi test of test calculator. piy crossing my fingers as always and now oh my God there's even more errors on the screen but this in itself is more helpful let's work through them from top to bottom so under failures here in all caps which I know is not very encouraging to see failure when you're just trying to solve a problem but that's what these Frameworks do under failures the first function that failed is test positive but here too we see the same clue as before the first one two the square of two equals equals 4 that one's fine it's not airing with any red errors but the next one is failing so I know that square is broken when I pass in three all right what about down here it looks like unfortunately my test negative function is failing to why well when I pass in oh this is interesting here now -2 doesn't even work so I got lucky with positive two but negative -2 isn't working so that's a bit of a clue but in total only two tests failed so notice at the very bottom this summary two failed and one passed what's the other one what was the third one test zero so test zero is passing these two are failing and so that kind of leads me logically mathematically if you will to the source of the bug and just to be clear too if you have a lot of tests this little oneline output is helpful even though also a bit discouraging fail fail and Dot means pass so there are the three tests just depicted graphically a little bit differently well let me rewind now and go back into calculator. Pi let's fix that bug because let's suppose that I've deduced okay I'm using addition I should have been using multiplication all this time let me now after fixing the bug yet again let me go back to my big terminal let me run Pi test of test calculator. Pi hitting enter crossing my fingers now and dot dot dot means all is well 100% of my tests passed all three of them so now I'm good it doesn't necessarily mean that my code is 100% correct but it does mean that it has passed 100% of my current tests and so it would probably behoove us to think a little harder about maybe we should test bigger numbers maybe we should test even smaller numbers maybe we should test strings or something else the onus is ultimately on you to decide what you're going to test but in the real world you're going to be very unhappy with yourself or someone else maybe your boss is going to be very unhappy with you if you did not catch a bug in your code which you could have caught had you just written a test to try that kind of input all right let me pause again and see if there's any questions now on unit testings with P test um so if you wanted to test like someone suggested before user input as well as testing your function do you do that within the same file or do you make separate files for different types of test really good question you could absolutely make separate files to test different types of things or if you don't have that many you can keep them all in the same file at the moment I've been storing all of my tests in one file for convenience and there's not terribly many of them but we'll take a look in a bit at an example that allows me to put them into a folder and even run P test on a whole folder of tests as well so that's possible other questions on unit testing so I've got two questions um so a couple while ago you just used um an exception called assertion um I'm not sure what was oh yeah assertion error um what exactly does that particular error catch and my second question is does the assert keyword um stand out to the compiler and exactly tell them to assert this particular um line of code indeed the assert keyword we're seeing and the assertion error we saw earlier are intertwined so when you use assert and the assertion fails because whatever Boolean expression you're using is not true it's false an assertion error by definition of python will be raised so those two work in conjunction those errors those assertion errors are still being raised by my code here when any of these lines of code fail however pest this third party library is handling the process of catching those exceptions automatically for me so as to give me the standard output so we started to today's Story by really implementing unit testing myself I wrote all of the code myself I wrote main I did my conditional I did try except honestly it's going to get incredibly painful to write tests long term if you and I have to write that much code every time especially when our function is this small uh so pie test and unit testing Frameworks like it just automate so much of that essentially P test adds the try the accept the if the prints for you so you can just focus on the essence of the tests which really are these inputs and outputs how about time for one other question here on unit testing as well sir uh when we uh enter minus 6 or minus5 uh the uh square or Square uh square root of the that uh number comes up but when we put 6.6 or 5.6 something like that integer then uh line shows error so what's happening there so if I'm deliberately testing integers right now in large part because I only want pow to operate on inte ERS and that might be conveyed in Python's documentation or my own documentation for that function if we were to pass in something else like a float it turns out that floating Point values in Python and other languages are actually very hard if not impossible to represent 100% precisely and so if you are trying to compare it against some other value they might be slight rounding errors as a result I'm just inferring from what you've described but I'm very deliberately now testing this function with only the inputs that I would expect it might indeed throw other errors if other inputs are passed all right allow me to propose that we consider what should happen if Square isn't actually passed a number for instance if I go back to calculator. Pi and suppose that I or perhaps someone else using my Square function simply forgets to convert the return value of input from a stir to an INT as by modifying line two here well now something's definitely going to go wrong if I type in a stir instead of what appears to be an INT for instance if I clear my terminal here run pip Pyon of calculator. Pi and hit enter let's type in cat as our value for x and of course this raises Now a type error why can't multiply sequence by non-int of type stir what does that mean well you can't do cat times cat because indeed square is expecting that n will be some number but that doesn't necessarily mean that square itself is buggy but this does mean that if I expect a type error to be raised let's test for that too so that I know the behavior indeed works as expected so let me go back to test calculator p and let me go and add a fourth test down here how about Define testore and I'll call this tester because I'm going to specifically and deliberately pass in a stir for testing and I want to in spirit assert that passing in something like cat to square will raise a type error but we don't use the assert keyword for that rather we need this let me go to the top of this file and let me additionally import the pest Library itself because it turns out there's a function in that Library called raises that allows me to express that I expect an exception to be raised and I can express that as follows with pest. raises and then in parenthesis I can pass in the type of exception I expect which is going to be a type error in this case and now when do I expect that type error to be raised whenever I do something like calling square and passing in not a number but something like cat so now if I go back to my terminal window run Pi test of test calculator. piy this time having four tests I should see that all four now are successful all right let's now consider how we could test code that doesn't just expect numbers as input but actually strings and let me rewind Us in time here in VSS code to that very first program rewrote a few different versions of in hello.py that ultimately looked a little something like this I had a main function that prompted the user for the value of a variable by asking them what's your name question mark and then we went ahead and did something like hello open pen name passing that user's name into a function called hello now that function hello recall ultimately looked like this we defined hello as taking a parameter called two the default value of which was world and that function very simply printed hello followed by a comma and then whatever the name that had been passed in and then we ultimately called main but for now onward I'm going to always add this if conditional if name equals equals underscore uncore main then and only then do I want to call Main so that's essentially what this program looked like in its last Incarnation how do we go about testing it well here again too I'm not going to test the user's input per se in main I'm going to focus really on the module the module of code here that's of Interest which is the hello function itself how can I go about testing the hello function well unfortunately even if I start by doing something like code of test hello.py let me go about and start writing a test program I could import from my hello program a function called hello so a bit strange to see from Hello import hello but notice that on this line here I'm importing from the module that is the file called hello.py the function called hello and how do I go about testing this well if I have a function like Define uh test argument like this well let me Sue this so if I were toine a function like like Define test hello what could I do well I could call hello with quote unquote say uh David and then check if it equals what hello comma David so would this work this approach here if I've written a test called test hello that calls hello with an argument of David and then tests its return value just like we've done for our calculator would this work as written and let me go back to in just a moment the version of hello that we're testing so you can see that function hello here's the test here is the actual code would this test now work any thoughts uh I think the problem is that in the first version in hello.py you're using the toe argument that you first declare when you declare the function instead of using the name okay I that is actually uh not a bug here so let me stipulate that in hello.py this code actually does work as intended and let me go ahead and test it manually just to demonstrate as much let me run python of hello.py typing in as my name David and I see in fact that it says hello David if though I were to change this program and get rid of the name argument get rid of the name variable and just call hello again running python of hello.py this time I'm not even prompted because I got rid of my input call but it does pre behave as I expect it does say hello world so let me stipulate that this code in its current form is actually correct but my test is not going to work as I'd hoped and there's a subtle difference between hello versus my pow function that expl versus my there's a subtle difference between my hello function and my Square function that explains why might this test not work as intended um because it's not returning a value yeah exactly recall our discussion early on about functions functions can either return a value like my Square function hands you back the square of some value or they can have side effects sort of visual uh artifacts that might happen on the screen like printing something out on the screen and by definition that's how Print Works notice that hello it is short but it's implemented ultimately using the print function which does not return a value as I'm using it here it instead has this side effect of printing something onto the screen so it is not correct in my test function to check if the return value of hello equals equals hello David because again hello is not returning anything it's printing something with that side effect but notice literally it has no return keyword unlike my Square function which did so here's an opportunity too to perhaps change how I go about implementing my actual functions it turns out that as your programs get more and more sophisticated more and more complicated it tends to be best practiced not to have side effects if if you can avoid it especially if you want your code to be testable and in fact I'm going to propose that we change my hello program to now work as follows let me go ahead and change this function to not print hello and then that name let me go ahead and literally return maybe an F string which will clean this up a little bit hello comma 2 close quote at the end so my syntax here is just the familiar F string or format string it's going to return hello world or hello David or hello whoever name is passed in as that argument but I'm returning it now I'm not printing it out so what needs to change up here well I could do something like this I could say something like output equals hello and then print output in my main function or I can simplify that because I don't really need that variable I could instead just do this I could still call hello but I could immediately print out the result and this version of my hello program now is actually more test able why because these assert statements that we're using and we've seen th far for our tests are really designed to test arguments into functions and return values there from not testing side effects so if you're doing equals equals you're looking for a return value something that's handed back from the function so that's fine if I modify the design of my program now not to just print hello but to return the string the sentence the phrase that I want to construct I can leave it to the caller that is the function who's using this hello function to handle the actual printing now what does this mean in my code well it means now if my hello.py looks like this and hello is indeed returning a value in my test hello function I can test it exactly like this so let me go ahead and run Pi test of test hello.py crossing my fingers as always and voila one passed so I passed this test because apparently the return value of hello does indeed equal hello comma David well let's test the scenario what if I P call hello without any arguments let's assert that calling hello with nothing in those parentheses similarly equals hello comma but world the default value let me now go ahead and run Pi test of test hello.py and that too passes entirely but there too suppose that I had made some mistake suppose that there were a bug in my code it might not be best practice to combine multiple tests in this one function so let's make it more clear what might pass or fail let's call the first function test the default uh to this function and let's only include this first line of code and then let's go ahead and Define another function like test argument to test this other line of code here so now I have two different tests Each of which is testing something a little fundamentally different so now when I run my code it's still not broken if I run Pi test of test hello.py enter I've now passed two tests and that's just as good as before but if I did have a bug having two tests instead of one would indeed give me perhaps a bit more of a hint as to what's wrong questions now on this testing of return values when these return values are now strings instead of integers and why we've done this so my question is uh about function inside the function uh can we test that too or recursion we we we have't seen if you have if you have a recursive function which we've not discussed in this class yes you can absolutely test those two uh by simply calling them exactly in this way recursion does not affect this process all right how about one more question here on unit test before we look at one final example when testing our uh arguments like uh can we use something like a Loops or inside of assert or for the values absolutely you can absolutely use a loop to test multiple values in this case for instance I could do something like this I could say for name in The Following list of Hermione uh say Harry and Ron I could then within this Loop assert that hello of that given name equals equals say the format string of hello comma name and then run all of these here at once by running again Pi test of test hello.py it's still going to be just one test within that function but if there's something interesting about those several strings that makes it compelling to test all of them you can absolutely automate the tests in that way with that said each of your test should ideally be pretty simple and pretty small why because you don't want to write so much code so much complicated code that your tests might be flawed what we don't want to have to do is write tests for our tests and tests for our test for our tests because it would never end so keeping tests nice and simple is really the goal so that a reasonable human yourself included can eyeball them and just claim yeah that is correct we don't need tests for our tests all right how about one other feature suppose that we don't have just one test but many different tests instead and we want to start to organize those tests into multiple files and even a folder well P test and other Frameworks support that Paradigm as well in fact let me go ahead and test hello.py using a folder of tests with technically just one test but it would be representative of having even more in that folder I'm going to go ahead and create a new folder called test using makeer at my command line and then Within that file I'm within that and then within that folder I'm going to go ahead and create a file called test hello.py within this file meanwhile I'm going to test the same things I'm going to go ahead and from Hello import hello and I'm going to go ahead and Define a function like test default that simply tests the scenario where hello with no arguments returns hello comma world and I'm going to have that other function where I test that an argument is passed and in this case I'll choose an argument like asserting that hello quote unquote David equals indeed hello comma not world but David So in this case I've just recreated the same test as earlier but they're in a file now in a folder called test well P test allows me to run these here too but to do so I actually need to create one other file within my test directory I need to create a file called uncore uncore init uncore uncore dopy which has the effect even if this file is empty of ing python to treat that folder as not just a module but a package so to speak a package is a python module or multiple modules that are organized inside of a folder and this file underscore uncore init underscore uncore Pi is just a visual indicator to python that indeed it should treat that folder as a package if I had more code in this folder I could do even more things with this file but for now it's just a cluee that it's indeed meant to be a package and not just a module or file alone what I can now do in closing is run P test not even on that specific file but on a whole folder of tests so if I run Pest of test where the test is the name of that folder pest will automatically search through that folder looking for all possible tests granted there's just those two in this one file but when I run it now with enter I'll still pass those tests I'll still get 100% And I now have a mechanism ultimately for testing my own code so whether you're writing functions that return integers or something else functions that have side effects that could be Rewritten as functions that return values you now have a mechanism to not just wait for one someone like us to test your code and not just test your code manually again and again which might get tedious and you might make mistakes by not including some possible inputs we now have an automated mechanism for testing one's own code that's going to be even more powerful when you start collaborating with others so that you can write tests that ensure that if they make a change to the same code they haven't broken the code that you've written all right that's it for this week we'll see you next time [Music] [Music] all right this is cs50's Introduction to programming with python my name is David men and this is our week on file IO input and output of files so up until now most every program we've written just stores all the information that it collects in memory that is in variables or inside of the program itself a downside of which is that as soon as the program exits anything you typed in anything that you did with that program is lost now with files of course on your Mac or PC you can hang on to information long term and file IO within the context of programming is all about writing code that can read from that is load information from or write to that is save information to files themselves so let's see if we can't transition then from only using memory and variables and the like to actually writing code that save some files for us and therefore data persistently well to do this let me propose that we first consider a familiar data structure a familiar type of variable that we've seen before that of a list and using lists we've been able to store more than one piece of information in the past using one variable we typically store one value but if that variable is a list we can store multiple values unfortunately lists are stored in the computer's memory and so once your program exits even the contents of those disappear but let's at least give ourselves a starting point so I'm over here in vs code and I'm going to go ahead and create a simple program using Code of names. py a program that just collects people's names students names if you will and I'm going to do it super simply initially in a manner consistent with what we've done in the past to get user input and print it back out I'm going to say something like this name equals input quote unquote what's your name thereby storing in a variable called name the return value of input as always and as always I'm going to go ahead and very simply print out a nice F string that says hello comma and then in curly brace's name to print out hello David hello world however happens to be using the program let me go ahead and run this just to remind myself what I should expect and if I run python of names. high and hit enter type in my name like David of course I now see hello comma David suppose though that we wanted to add support not just for one name but multiple names maybe three names for the sake of discussion so that we can begin to accumulate some amount of information in the program such that it's really going to be a downside if we keep throwing it away once the program exits well let me go back into names. up here at top let me proactively give myself a variable this time called names plural and set it equal to an empty list recall that the square bracket notation especially if nothing's inside of it just means give me an empty list that we can add things to over time well what do we want to add to it well let's add three names each from the user and let me say something like this uh for underscore in range of three let me go ahead and prompt the user with the input function and getting their name in this variable and then using list syntax I can say names. append name to that list list and now I have in that list that given name one two three of them other points to note is I could use a variable here like I which is conventional but if I'm not actually using I explicitly on any subsequent lines I might as well just use underscore which is a pythonic convention and actually if I want to clean this up a little bit right now notice that my name variable doesn't really need to exist because I'm assigning it a value and then immediately appending it well I could tighten this up further by just getting rid of that variable Al together and just appending immediately the return value of input I think we could go both ways in terms of design here on the one hand it's a pretty short line and it's readable on the other hand if I were to eventually change this phrase to be not what's your name but something longer we might want to break it out again into two lines but for now I think it's pretty readable now later in the program let's just go ahead and print out those same names but let's sort them alphabetically so that it makes sense to be gathering them all together then sorting them and printing them so how can I do that well in Python the simplest way to sort a list in a loop is probably to do something like this for name in names but wait let's sort the names first recall that there's a function called sorted which will return a sorted version of that list now let's go ahead and print out uh an F string that says again hello bracket name close quote all right let me go ahead and run this so Python ofn names. and let me go ahead and type in a few names this how about hermion how about Harry how about Ron and notice that they're not quite in alphabetical order but when I hit enter and that Loop kicks in it's going to print out hello Harry hello Hermione hello Ron in sorted order but of course now if I run this program again all of the names are lost and if this is a bigger program than this that might actually be pretty painful to have to re-input the same information again and again and again wouldn't it be nice like most any program today on a phone or or a laptop or desktop or Cloud to be able to save this information somehow instead and that's where file IO comes in and that's where Files come in they are a way of storing information persistently on your own phone or Mac or PC or some Cloud servers uh disk so that they're there when you come back and run the program again so how can we go about saving all three of these names on in a file as opposed to having to type them again and again let me go ahead and simplify this file and again give myself just a single variable called name and set the return value of input equal to that variable so what's your name as before quote unquote and now let me go ahead and let me do something more with this value instead of just adding it to a list or printing it immediately out let's save the value of the person's name that's just been typed in to a file well how do we go about doing that well in Python there's this function called open whose purpose in life is to do just that to open a file but to open it up Pro grammatically so that you the programmer can actually read information from it or write information to it so open is like the programmer's equivalent of like double clicking on an icon on your Mac or PC but it's a programmer's technique because it's going to allow you to specify exactly what you want to read from or right to that file formally its documentation is here and you'll see that its usage is relatively straightforward it minimally just requires the name of the file that we want to open and optionally how we want to open it so let me go back back to vs code here and let me propose now that I do this I'm going to go ahead and call this function called open passing in an argument for names.txt which is the name of the file I would like to store all of these names in I could call it anything I want but because it's going to be just text it's conventional to call it something. txt but I'm also going to tell the open function that I plan to write to this file so as a second argument to open I'm going to put literally quote unquote W for right and that's going to tell open to open the file in a way that's going to allow me to change the content and better yet if it doesn't even exist yet it's going to create the file for me now open returns what's called a file handle a special value that allows me to access that file subsequently so I'm going to go ahead and sign it equal to a variable like file and now I'm going to go ahead and quite simply write this person's name to that file so I'm going to literally type file which is the variable uh linking to that file WR which is a function otherwise known as a method that comes with open files that allows me to write that name to the file and then lastly I'm going to quite simply going to go ahead and say file. close which will close and effectively save the file so these three lines of code here are essentially the programmers equivalent to like double clicking an icon on your Mac or PC making some changes in Microsoft Word or some other program and going to file save we're doing that all in code with just these three lines here well let's see now how this works let me go ahead now and run python of names. piy and enter let's type in a name I'll type in her Mayan enter all right where did she end up well let me go ahead now and type code of names.txt which is a file that happens now to exist because I opened it in right mode and if I open this in a tab we'll see there is Hermione well let's go ahead and run names. py once more I'm going to go ahead and run python of names. py enter and this time I'll type in Harry let me go ahead and run it one more time and this time I'll type in Ron and now let me go up to names. text where hopefully I'll see all three of them here but no I've just actually seen Ron What might explain what happened to Hermione and Harry even though I'm pretty sure I ran the program three times and I definitely wrote the code that writes their name to that file what's going on here do you think I think because we are not appending them we should append the names uh since we are writing directly it is erasing the old content and it is replacing with the last uh um set of characters that we mentioned exactly unfortunately quote unquote W is a little dangerous not only will it create the file for you it will also recreate the file for you every time you open the file in that mode so if you open the file once and write Hermione that worked just fine as we saw but if you do it again for Harry if you do it again for Ron the code is working but each time it's opening the file and recreating it with brand new contents so we had one version with Hermione one version with Harry and one final version with Ron but ideally I think we probably want to be appending as bashall says each of those names to the file not just clobbering that is overwriting the file each time so how can I do this it's actually a relatively easy fix let me go ahead and do this as follows I'm going to first remove the old version of names. text and now I'm going to change my code to do this I'm going to change the W quote unquote to just a quote unquote a for aend which means to add to the bottom to the bottom to the bottom again and again now let me go ahead and rerun python of names. piy enter I'll again start from scratch with hermion because I'm creating the file new notice that if I now do code of names.txt enter we do see that hermion is back so we've after removing the file it did get Rec created even though I'm using a pend which is good but now let's see what happens when I go back to my terminal and this time I run python of names. py again this time typing in Harry and let me run it one more time this time typing in Ron so hopefully this time in that second tab names. text I should now see all three of them but but but but this doesn't look ideal what have I clearly done wrong something tells me even though all three names are there it's not going to be easy to read those back unless you know where each name ends and Begins the English format is not correct like the English format is not correct like it's say correct it's concatenating them it is it's it's in can it's well it appears to be concatenating but technically speaking it's just a pending to the file first Hermione then Harry then Ron it has the effect of combining them back to back but it's not concatenating per se it really is just a pending let's go to another hand here what really have I done wrong or equivalently how might I fix it would be nice if there were some kind of gaps between each of the names so we could read them more cleanly Hello uh we should uh add new line before we uh write new name good we want to add a new line ourselves so whereas print by default recall always outputs automatically a line ending of back sln unless we override it with the named parameter called n and right does not do that right takes you literally and if you say WR Hermione that's it you're getting the H through the E if you say right hairry you get the H through the Y you don't get any extra new lines automatically so if you want to have a new line at the end of each of these names we've got to do that manually so let me again Clos names. text and let me remove the current file and let me go back up to my code here and I can fix this in any number of ways but I'm just going to go ahead and do this I'm going to write out an F string that contains name and back sln at the end we could do this in different ways we could manually print just the new line or some other technique but I'm going to go ahead and use my f strings as I'm in the habit of doing and just print the name and the new line all at once I'm going to go ahead now and down to my terminal window run python of names. py again enter we'll type in Hermione I'm going to run it again type in Harry I'm going to type it again and this time Ron now I'm going to run code of names.txt and open that file and now it looks like the file is a bit cleaner indeed I have each of the name on its own line as well as a line ending which ensures that uh we can separate one from the other now if I were you know writing code I bet I could parse that is read the previous file by looking at differences between lowercase and uppercase letters but that's going to get messy quickly generally speaking when storing data longterm in a file you should probably do it somehow cleanly like doing one name at a time well let's now go back and I I'll propose that this code is now working correctly but we can design it a little bit better it turns out that it's all too easy when writing code to sometimes forget to close files and sometimes this isn't necessarily a big deal but sometimes it can create problems files could get corrupted or accidentally deleted or the like depending on what happens in your code so it turns out that you don't strictly need to call close on the file yourself if you take another approach instead more pythonic when M uh manipulating files is to do this to introduce this other keyword called quite simply with that allows you to specify that in this context I want you to open and automatically close some file so how do we use with it simply looks like this let me go back to my code here I've gotten rid of the close line and I'm now just going to say this instead instead of saying file equals open I'm going to say with open then the same arguments as before and somewhat curiously I'm going to put the variable at the end of the line why that's just the way this is done you say with you call the function in question and then you say as and specify the name of the variable that should be assigned the return value of open then I'm going to go ahead and indent the line underneath so that the line of code that's writing the name is now in the context of this withth statement which just ensures that automatically if I had more code in this file down below no longer indented the file would be automatically closed as soon as line four is done executing so it doesn't change what has just happen but it does automate the process of at least closing things for us just to ensure I don't forget and so that something doesn't go wrong but suppose now that I wanted to read these names from the file all I've done thus far is write code that writes names to the file but let's assume now that we have all of these names in the file and heck let's go ahead and add one more let me go ahead and run this one more time python of names. py and let's let in Draco to the mix so now that we have all four of these names here how might we want to re them back well let me propose that we go into names. now or we could create another program Al together but I'm going to keep reusing the same name just to keep us focused on this and now I'm going to write code that reads an existing file with Hermione Harry Ron and Draco together and how do I do this well it's similar in spirit I'm going to start this time with with open and then the first argument is going to be the name of the file that I want to open as before and I'm going to open it this time in read mode quote unquote r and to read a file just means to load it not to save it and I'm going to name the return value file and now I'm going to do this and there's a number of ways I can do this but one way to read all of the lines from the file at once would be this let me declare a variable called lines let me access that file and call a function or a method that comes with it called read lines so if you read the documentation on file IO in Python you'll see that open files come with a special method whose purpose in life is to read all the lines from the file and return them to me as a list so what this line two is doing is it's reading all of the lines from that file storing them in a variable called lines now suppose I want to iterate over all of those lines and print out each of those names for line in lines this is just a standard for Loop in Python lines is a list line is the variable that will be automatically be set to each of those lines let me go ahead and print out something like oh hello uh comma and then I'll print out the line itself all right so let me go to my terminal window run python of names. py now I have not deleted names.txt so it still contains all four of those names and hit enter and okay it's not bad but it's a little ugly here what's going on when I ran names. py it's saying hello to hermion to Harry to Ron to Draco but there's these gaps now between the lines what's explains that symptom if if nothing else it just looks ugly it happens because in the text file we have a new line symbols uh in between those names and the print always adds another new line at the end so you you use the same symbol twice perfect and here's a good example of a bug a mistake in a program but if you just think about those first principles like how do each of the lines of code work that I'm using you should be able to reason exactly as Rafal did there to say that all right well one of those new lines is coming from the file after each name and then of course print all of these Weeks Later is still giving us for free that extra new line so there's a couple possible solutions I could certainly do this which we've done in the past and pass in a named argument to print like end equals quote unquote and that's fine I would argue a little better than that might actually be to do this to strip off of the end of the line the actual new line itself so that print is handling the printing of everything the person's name as well as the new line but you're just stripping off what is really just an implementation detail in the file we chose to use new lines in my text file to separate one name from another so arguably it should be a little cleaner in terms of design to strip that off and then let print print out what is really just now a name but that's ultimately a design decision the effect is going to be exactly the same well if I'm going to open this file and read all the lines and then iterate over all of those lines and print them each out I could actually combine this into one thing because right now I'm doing twice as much work I'm reading all of the lines then I'm iterating over all of the lines just to print out each of them well in Python with files you can actually do this I'm going to erase almost all of these lines now keeping only the width statement at top and inside of this width statement I'm going to say this for line in file go ahead and print out quote unquote hello comma and then line. rstrip so I'm going to take the approach of stripping off the end of the line but notice how elegant this is so to speak I've opened the file in line one and if I want to iterate over every line in the file I don't have to very explicitly load all read all the lines then iterate over all of the lines I can combine this into one thought it in Python you can simply say for line in file and that's going to have the effect of giving you a for Loop that iterates over every line in the file one at a time and on each iteration updating the value of this variable line to be Hermione then Harry then Ron than Draco so this again is one of the appealing aspects of python is that it reads rather like English for line and file print this it's a little more compact when written this way well what if though I don't want quite this Behavior because notice now if I run python of names. piy it's correct I'm seeing each of the names and each of the hos and there's no Extra Spaces in between but just to be difficult I'd really like us to be sorting these hellos really I'd like to Draco first then Harry then Hermione then Ron no matter what order they appear in the file so I could go in of course to the file and manually change the file but if that file is changing over time based on who is typing their name into the program that's not really a good solution in code I should be able to load the file no matter what it looks like and just sort it all at once now here is a reason to not do what I've just done I can't iterate over each line in the file and print it out but sort everything in advance right logically if I'm looking at each line one at a time and printing it out it's too late to sort I really need to read all of the lines first without printing them sort them then print them so we have to take a step back in order to add now this new feature so how can I do this well let me combine some ideas from before let me go ahead and start fresh with this let me give myself a list called names and assign it in empty list just so I have a variable in which to accumulate all of these lines and now let me open the file with open quote unquote names. text and it turns out I can tighten this up a little bit it turns out if you're opening a file to read it you don't need to specify quote unquote r that is the implicit default so you can tighten things up by just saying open names. text and you'll be able to read the file but not write it I'm going to give myself a variable called file as before I am going to iterate over the file in the same way for line in file but instead of printing each line I'm going to do this I'm going to take my name's list list and append to it and this is appending to a list in memory not appending to the file itself I'm going to go ahead and append the current line but I'm going to strip off the new line at the end so that all I'm adding to this list is each of the students names now I can use that familiar technique from before let me go outside of this with statement because now I've read the entire file presumably so by the time I'm done with lines four and five again and again and again for each line in the file I'm done with the file it can close I now have all of the students names in this list variable let me do this for name in not just names but the sorted names using our python function sorted which does just that and do print quote unquote with an FST string hello comma and now I'll plug in bracket name so now what have I done I'm creating a list at the beginning just so I have a place to gather my data I then on lines 3 through five iterate over the file from Top top to bottom reading in each line one at a time stripping off the new line and adding just the students name to this list and the reason I'm doing that is so that on line seven I can sort all of those names now that they're all in memory and print them in order I need to load them all into memory before I can sort them otherwise I'd be printing them out prematurely and Draco would end up last instead of first so let me go ahead in my terminal window and run python of names. py now and hit enter and there we go the same list of four hellos but now they're sorted and this is a very common technique when dealing with files and information more generally if you want to change that data in some way like sorting it creating some kind of variable at the top of your program like a list adding or appending information to it just to collect it in one place and then do something interesting with that collection that list is exactly what I've done here now I should note that if we just want to sort the file we can actually do this even more simply in Python particularly by not bothering with this names list nor the second for Loop and let me go ahead and instead just do more simply this let me go ahead and tell python that we want the file itself to be sorted using that same sorted function but this time on the file itself and then inside of that for Loop let's just go ahead and print right away our hello comma followed by the line itself but still stripping off of the end of it any white space therein if we go ahead and run this same program now with python of names. py and hit enter we get the same result but of course it's a lot more compact but for the sake of discussion let's assume that we do actually want to potentially make some changes to the data as we iterate over it so let me undo those changes leave things as is whereby now we'll continue to accumulate all of the names first into a list maybe do something to them maybe forcing them to uppercase or lower case or the like and then sort and print out each item let me pause and see if there's any questions now on file IO reading or writing or now accumulating all of these values in some list hi it's is there a way to sort the files but instead if you want it from alphabetically from A to Z is there a way to reverse it from Z to A is there like a little extension that you can add to the end to do that or would you have to create a new function if you wanted to reverse the contents of the file yeah so if you instead of sorting them from a to z in ascending order if you wanted them in descending order is there an extension for that there is indeed and as always the documentation is your friend so if the goal is to sort them not in alphabetical order which is the default but maybe reverse alphabetical order you can take a look for instance at the formal python documentation there and what you'll see is this summary you'll see that the sorted function takes a first argument generally known as an iterable and something that's iterable means that you can iterate over it that is you can Loop over it one thing at a time what the rest of this line here means is that you can specify a key like how you want to sort it but more on that later but this last named parameter here is reverse and by default per the documentation it's false it will not be reversed by default but if we change that to true I bet we can do that so let me go back to vs code here and do just that let me go ahead and pass in a second argument to sorted in addition to this iterable which is my names list iterable again in the sense that it can be looped over and let me pass in Reverse equals true thereby overwriting the default of false let me now run python of names. piy and now Ron's at the top and draco's at the bottom so there too whenever you have a question like that moving forward consider what does the documentation say and see if there's a germ of an idea there because oddar if you have some problem oddar some programmer before you has had the same question other thoughts uh can we limit uh number uh numbers of names and the second question uh can we find specific name in least really good question can we limit the number of the names in the file and can we find a specific one we absolutely could if we were to write code we could for instance open the file first count how many lines are already there and then if there's too many already we could just exit with cy. exit or some other message to indicate to the user that sorry the class is full as for finding someone specifically absolutely you could imagine opening the file iterating over it with a for loop again and again and then adding a conditional like if the current line equals equals Harry then we found the chosen run and you can print something like that so you can absolutely combine these ideas with previous ideas like conditionals to ask those same questions how about one other question on file IO uh so I just thought about um this function like uh read all lines and uh it looks like it's uh like separate all the lines by this special character back sln but it looks like we don't need it character and we we always strip it uh and uh it looks like some bad design of function why why wouldn't we just strip it inside this function a really good question so we are in my examples thus far using our strip to reverse uh to strip from the end of the line all of this white space you might not want to do that in this case I am stripping it away because I know that each of those lines isn't some generic line of text each line really represents a name that I have put there myself I'm using the new line just to separate one value from another in other scenarios you might very well want to keep that line ending because it's a very long series of text or a paragraph or something like that where you want to keep it distinct from the others but it's just a convention we have to use something presumably to separate one uh chunk of text from another there are other functions in Python that will in fact handle the removal of that white space for you read lines though does literally that though it reads all of the lines as is well allow me to turn our attention back to where we left off here which is just names to propose that with names. text we have an ability it seems to store each of these names pretty straightforwardly but what if we wanted to keep track of other information as well suppose that we wanted to store information including a student's uh name and their house at Hogwarts be it Gryffindor or Slytherin or something else well where do we go about putting that you know Hermione lives in Gryffindor so we could do something like this in our text file Harry lives in Gryffindor so we could do that Ron lives in Gryffindor so we could do that and Draco lives in Slytherin so we could do that but I worry here but I worry now that we're mixing apples and oranges so to speak like some lines are names some lines are houses so this probably isn't the best design if only because it's confusing or it's ambiguous so maybe what we could do is Adopt A convention and indeed this is in fact what a lot of programmers do they change this file not to be names. text but instead let me create a new file called names. CSV CSV stands for comma separated values and it's a very common convention to store multiple pieces of information that are related in the same file and so to do this I'm going to separate each of these types of data not with another new line but simply with a comma I'm going to keep each student on their own line but I'm going to separate the information about each student using a comma instead and so now we sort of have a a two-dimensional file if you will row by row we have our students but if you think of these commas as representing a column even though it's not perfectly straight because of the lengths of these names it's a little ra it's a little uh Jagged you can think of these commas as representing a column and it turns out these CSV files are very commonly used when you use something like Microsoft Excel Apple numbers or Google spreadsheets and you want to export the data to share with someone else as a CSV file or conversely if you want to import a CSV file into your preferred spreadsheet software like Excel or numbers or Google spreadsheets you can do that as well so CSV is a very common very simple text format that just separates values with commas and different types of values ultimately with new lines as well let me go ahead and run code of students. CSV to create a brand new file that's initially empty and we'll add to it those same names but also some other information as well so if I now have this new file students. CSV inside of which is one column of names so to speak and one column of houses how do I go about changing my code to read not just those names but also those names and houses so that they're not all on one line we somehow have access to both type of value separately well let me go ahead and create a new program here called uh students. py and in this program let's go about reading not a text file per se but a specific type of text file a CSV a comma separated values file and to do this I'm going to use similar code as before I'm going to say with open quotee unquote students. CSV I'm not going to bother specifying quote unquote R because again that's the default but I'm going to give myself a variable name of file and then in this file I'm going to go ahead and do this for line in file as before and now I have to be a bit clever here let me go back to students. CSV looking at this file and it seems that on my loop on each iteration I'm going to get access to the whole line of text I'm not going to automatically get access to just Hermione or just Gryffindor recall that the loop is going to give me each full line of text so logically what would you propose that we do inside of a for Loop that's reading a whole line of text at once but we now want to get access to the individual values like Hermione and Gryffindor Harry and Gryffindor how do we go about taking one line of text and gaining access to those individual values do you think just instinctively even if you're not sure what the name of the functions would be you can access access as you would as if you were using a dictionary like using a key and value so ideally we would access it using it a key and value but at this point in the story all we have is this Loop and this Loop is giving me one line of text at is a time I'm the programmer now I have to solve this there is no dictionary yet in question how about another suggestion here um so you can somehow split the two words based on the comma yeah even if you're not quite sure what function is going to do this intuitively you want to take this whole line of text hermion comma Gryffindor Harry comma Gryffindor and so forth and split that line into two pieces if you will and it turns out wonderfully the function we'll use is actually called split that can split on any characters but you can tell it what character to use so I'm going to go back into students. py and inside of this Loop I'm going to go ahead and do this I'm going to take the current line I'm going to remove the white space at the end as always using rst strip here and then whatever the result of that is I'm going to now call split and quote unquote comma so the split function or method comes with strings stirs in Python any stir has this method built in and if you pass in an argument like a comma what this stri split function will do is split that current string into one two three maybe more pieces by looking for that character again and again ultimately strip uh ultimately split is going to return to us a list of all of the individual parts to the left and to the right of those commas so I can give myself a variable called row here and this is a common Paradigm when you know you're iterating over a file specifically a CSV it's common to think of each uh line of it as being a row and each of the values therein separated by commas as columns so to speak so I'm going to deliberately name my variable row just to be consistent with that convention and now what do I want to print well I'm going to go ahead and say this print how about the following uh in F string that starts with curly braces well how do I get access to the first thing in that row well the row is going to have how many parts two because if I'm splitting on commas and there's one comma per line that's going to give me a left part and a right part like hermion and Gryffindor Harry and Gryffindor when I have a list like row how do I get access to individual values well I can do this I can say Row Bracket zero and that's going to go to the first element of the list which should hopefully be the student's name then after that I'm going to say is in and I'm going to have another curly brace here for Row Bracket one and then I'm going to close my whole quote so it looks a little cryptic at first glance but most of this is just F string syntax with curly braces to plug in values and what values am I plugging in well row again is a list and it has two elements presumably Hermione in one and Gryffindor in the other and so forth so bracket zero is the first element cuz remember we start indexing at zero in Python and one is going to be the second element so let me go ahead and run this now and see what happens python of uh students. py enter and we see hermion is in Gryffindor Harry's in Gryffindor Ron is in Gryffindor and Draco is in Slytherin so we have now implemented our own code from scratch that actually parses that is reads and interprets a CSV file ultimately here now let me pause to see if there's any questions but we'll make this even easier to read in just a moment any questions on what we've just done here by splitting by comma so my question is uh can we uh edit any line of code anytime we want or uh the only option that we have is to append uh the lines or uh let's say if we want to let's say change Harry's uh house to let's say Slytherin or some other house yeah a really good question what if you want to in Python change a line in the file and not just uh a pen to the end you would have to implement that logic yourself so for instance you could imagine now opening the file and reading all of the contents in then maybe iterating over each of those lines and as soon as you see that the current name equals equals Harry you could maybe change his house to slitherin and then it would be up to you though to write all of those changes back to the file so in that case you might want to in simplest form read the file once and let it close then open it again but open for writing and change the whole file it's not really possible or easy to go in and change just part of the file though you can do it it's easier to actually read the whole file make your changes in memory then write the whole file out but for larger files where that might be quite slow you can be more clever than that well let me propose now that we clean this up a little bit because I actually think this is a little cryptic to read Row Bracket Z Row Bracket one it's it's not that well written at the moment I would say but it turns out that when you have a variable that's a list like row you don't have to throw all of those variables into a list you can actually unpack that whole sequence at once that is to say if you know that a function like split returns a list but you know in advance that it's going to return two values in a list the first and the second you don't have to throw them all into a variable that itself is a list you can actually unpack them simultaneously into two variables doing name comma house so this is a nice python technique to not only create but assign automatically in parallel two variables at once rather than just one so this will have the effect of putting the name in the left Hermione and it will have the effect of putting Gryffindor the house in the right variable and we now no longer have a row we can now make our code a little more readable by now literally just saying name down here and for instance house down here so just a little more readable even though functionally the code now is exactly the same all right so this now works and I'll confirm as much by just running it once more python of students. py enter and we see that the text is as intended but suppose for the sake of discussion that I'd like to sort this list of output I'd like to say hello again to Draco first then hello to Harry then Hermione then Ron how can I go about doing this well let's take some inspiration from the previous example where we were only dealing with names and instead do it with these full phrases so and so is in house well let me go ahead and do this I'm going to go ahead and start scratch and give myself a list uh called students equal to an empty list initially and then with open students. CSV as file I'm going to go ahead and say this for line in file and then below this I'm going to do exactly as before name comma house equals the current line stripping off the white space at the end splitting it on a comma so that's exact same as before but this time before I go about uh printing the sentence I'm going to store it temporarily in a list so that I can accumulate all of these sentences and then sort them later so let me go ahead and do this students which is my list do append let me append the actual sentence I want to show on the screen so another F string so name is in house just as before but notice I'm not printing that sent sentence I'm appending it to my list not a file but to my list why am I doing this well just because as before I want to do this for student in the sorted students I want to go ahead and print out student like this let me go ahead and run python of students. py and hit enter now and I think we'll see indeed Draco is now first Harry is second hermion is third and Ron is fourth but this is arguably a little sloppy right it seems a little hackish that I'm constructing these sentences and even though I'm technically want to sort by name I'm technically sorting by these whole English sentences so it's not wrong it's achieving the intended result but it's not really welld designed because I'm just kind of getting lucky that English is reading from left to right and therefore when I print this out it's sorting properly it would be better really to come up with a technique for sorting by the students names not by some English sentence that I've constructed here online six so to achieve this I'm going to need to make my life more complicated for a moment and I'm going to need to collect information about each student before I bother assembling that sentence so let me propose that we do this let me go ahead and undo these last few lines of code so that we currently have two variables name and house Each of which has name and the student's house respectively and we still have our Global variable students but let me do this recall that python supports dictionaries and dictionaries are just collections of keys and values so you can associate something with something else like a name with Hermione like a house with Gryffindor that really is a dictionary so let me do this let me temporarily create a dictionary that stores this Association of name with house let me go ahead and do this let me say that the student here is going to be represented initially by an empty dictionary and just like you can create an empty list with square brackets you can create an empty dictionary with curly braces so give me an empty dictionary that will soon have two keys name and house how do I do that well I could do it this way student Open Bracket name equals the student's name that we got from the line student bracket house equals the house that we got from the line and now I'm going to append to the students list plural that particular student now why have I done this I've admittedly made my code more complicated it's more lines of code but I've now collected all of the information I have about students while still keeping track what's a name what's a house the list meanwhile has all of the students names and houses together now why have I done this well let me for the moment just do something simple let me do for student in students and let me very Simply Now say print the following F string the current student with this name uh is in this current student house and now notice one detail inside of this F string I'm using my curly braces as always I'm using inside of those curly braces the name of a variable as always but then I'm using not bracket zero or one because these are dictionaries now not list but why am I using single quotes to surround house and to surround name why single quotes inside of this F string to access those keys yes um because you have double quotes in that in that line 12 and so you have to tell p python to differentiate exactly because I'm already using double quotes outside of the F string if I want to put quotes around any strings on the inside which I do need to do for dictionaries because recall when you index into a dictionary you don't use numbers like lists 0 1 two onward you instead use strings which need to be quoted but if you're already using double quotes it's easiest to then use single quotes on the inside so python doesn't get confused about what lines up with what so at the moment when I run this program it's going to print out those hellos but they're not yet sorted in fact what I now have is a list of dictionaries and nothing is yet sorted but let me tighten up the code too to point out that it doesn't need to be quite as verbose if you're in the habit of creating an empty dictionary like this on line six and then immediately putting in Keys name and house each with two values name and house respectively you can actually do this all at once so let me show you a slightly different syntax I can do this give me a variable called student and let me use curly braces on the right hand side here but instead of leaving them empty let's just Define those keys and those values now quote unquote name will be name and quote unquote house will be house this achieves the exact same effect in one line instead of three it creates a new non dictionary containing a name key the value of which is the student's name and a house key the value of which is the student's house nothing else needs to change that will still just work so that if I again run python of students. I'm still seeing those greetings but they're still not quite actually sorted well what might I go about doing here in order to what could I do to improve upon this further well we need some mechanism now of sorting those students but unfortunately you can't do this we can't sort all of the students now because those students are not names like they were before they aren't sentences like they were before each of the students is a dictionary and it's nonobvious how you would sort a a dictionary inside of a list so ideally what do we want to do if at the moment we hit hit line nine we have a list of all of these students and inside of that list is one dictionary per student and each of those dictionaries has two keys name and house wouldn't it be nice if there were a way in code to tell python sort this list by looking at this key in each dictionary because that would give this the ability to sort either by name or even by house or even by any other field that we add to that file so it turns out we can do this we can tell the sorted function not just to reverse things or not it takes another positional it takes another named parameter called key where you can specify what key should be used in order to sort some list of dictionaries and I'm going to propose that we do this I'm going to first Define a function temporarily for now called get name and this function's purpose in life given a student is to quite simply return the student's name from that particular dictionary so if student is a dictionary this is going to return literally the student's name and that's it that's the sole purpose of this function in life what do I now want to do well now that I have a function that given a student will return to me the student's name I can do this I can change sorted to say use a key that's equal to whatever the return value of get name is and this now is a feature of python python allows you to pass functions as arguments in two other functions so get name is a function sorted is a function and I'm passing in get name to sorted as the value of that key parameter now why am I doing that well if you think of the get name function as just a bunch a block of code that will get the name of a student that's handy because that's the capability that sorted needs when given a list of students Each of which is a dictionary sorted needs to know how do I get the name of the student in order to do alphabetical sorting for you the authors of python didn't know that we were going to be creating students here in this class so they couldn't have anticipated writing code in advance that specifically sorts on a field called student let alone called name name let alone house so what did they do they instead built into the sorted function this named parameter key that allows us all these years later to tell their function sorted how to sort this list of dictionaries so now watch what happens if I run python of students. py and hit enter I now have a sorted list of output why because now that list of dictionaries has all been sorted by the student's name I can further do this if as before we want to reverse the whole thing by saying reverse equals true we can do that too let me rerun python of students. and hit enter now it's revers now it's Ron than hermion Harry and Draco but we can do something different as well what if I want to sort for instance by house name reversed I could do this I could change this function from get name to get house I could change the implementation up here to be get house and I can return not the student's name but the student's house and so now notice if I run python of students. piy enter notice now it is sorted by house in reverse order Slytherin is first and then Gryffindor if I get rid of the reverse but keep the get house and rerun this program now it's sorted by house Gryffindor is first and Slytherin is last and the upside now of this is because I'm using this list of dictionaries and keeping the students data together until the last minute when I'm finally doing the printing I now have full control over the information itself and I can sort by this or that I don't have to constru construct those sentences in advance like I rather hack asly did the first time all right that was a lot let me pause here to see if there are questions so when when we sorting the files should we every time should we use the uh Loops or like a like a d dictionary or or any kind of list can we sort by just sorting now looping or any kind of stuff a good question and the short answer with python alone you're the programmer you need to do the Sorting with libraries and other techniques absolutely you can do more of this automatically because someone else has written that code what we're doing at the moment is doing everything from scratch ourselves but absolutely with other functions or libraries some of this could be made uh more uh easily done some of this could be made uh easier other questions on this technique here it equal to the returned value of the function can it be equal to just a a variable or a value it well yes it should equal a value so I'm spec and I should clarify actually since this was not obvious so when you pass in a function like get name or get house to the sorted function as the value of key that function is automatic ially called by the get by the sorted function for you on each of the dictionaries in the list and it uses the return value of get name or get house to decide what strings to actually use to compare in order to decide which is alphabetically correct so this function which you pass just by name you do not pass in parentheses at the end is called by the sorted function in order to figure out for you how to compare these same values how can we use nested dictionaries I have read about nested dictionaries what is the difference between Ned dictionaries and dictionary inside a list I think it is sure um uh so we are using a list of dictionaries why because each of those dictionaries represents a student and a student has a name in a house and we want to I claim maintain that Association and it's a list of students because we've got multiple students four in this case you could create a a structure that is a dictionary of dictionaries but I would argue it just doesn't solve a problem I don't need a dictionary of dictionary I need a list of key value pairs right now that's all so let me propose if we go back to students. py here and we revert back to the approach where we have get name as the function both used and defined here and that function Returns the student's name what happens to be clear is that the sorted function will use the value of key get name in in this case calling that function on every dictionary in the list that it's supposed to sort and that function get name Returns the string that sorted we'll actually use to decide whether things go in this order left right or in this order right left it alphabetizes things based on that return value so notice that I'm not calling the function get name here with parenthesis I'm passing it in only by its name so that the sorted function can call that get name function for me now it's turns out as always if you're defining something be it a variable or in this case a function and then immediately using it but never once again needing the name of that function like get name we can actually tighten this code up further I can actually do this I can get rid of the get name function Al together just like I could get rid of a variable that isn't strictly necessary and instead of passing key the name of a function I can actually Pass Key what's called in a Lambda function which is an a function a function that just has no name why because you don't need to give it a name if you're only going to call it in one place and the Syntax for this in Python's a little weird but if I do key equals literally the word Lambda then something like student which is the name of the parameter I expect this function to take and then I don't even type the return key i instead just say student bracket name so what am I doing here with my code this code here that I've highlighted is equivalent to to the get name function I implemented a moment ago the syntax is admittedly a little different I don't use def I didn't even give it a name like get name i instead I'm using this other keyword in Python called Lambda which says Hey python here comes a function but it has no name it's Anonymous that function takes a parameter I could call it anything I want I'm calling it student why because this function that's passed in as key is called on every one of the students in that list every one of the dictionaries in that list what do I want this Anonymous function to return well given a student I want to index into that dictionary and access their name so that the string Hermione and Harry and Ron and Draco is ultimately returned and that's what the sorted function uses to decide how to sort these bigger dictionaries that have other Keys like house as well so if I now go back to my terminal window and run python of students. it still seems to work the same but it's arguably a little better design because I didn't waste lines of Code by defining some other function calling it in one and only one place I've done it all sort of in one breath if you will all right let me pause here to see if there's any questions specifically about Lambda or Anonymous functions and this tightening up of the code and I had one question like whether we could Define Lambda twice can you you can use Lambda twice you can create as many Anonymous functions as you'd like and you generally use them in context like this where you want to pass to some other function uh a function that itself does not need a name so you can absolutely use it in more than one place I just have only one use case for it how about one other question on Lambda or Anonymous functions specifically what what if our Lambda would take more than one line for example if sure if your Lambda function takes multiple parameters that is fine you can simply specify commas follow by the names of those parameters maybe X and Y or so forth after the name student so here too Lambda looks a little different from DEA in that you don't have parentheses you don't have the keyword def you don't have a function name but ultimately they achieve that same effect they create a function anonymously and allow you to pass it in for instance as some value here so let's now change students. CSV to contain not students houses at Hogwarts but their homes where they grew up so Draco for instance grew up in Malfoy Manor uh Ron grew up in the burrow uh Harry grew up in uh number four privet drive and according to the internet no one knows where hermion grew up the movies apparently took certain liberties with where she grew up so for this purpose we're actually going to remove Hermione because it is unknown exactly where she was born so we still have some three students but if anyone can spot the potential problem now how might this be a bad thing well let's go and try and run our own code here let me go back to students. py here and let me propose that I just change my semantics because I'm now not thinking about Hogwarts houses but the students own home so I'm just going to change some variables I'm going to change this house to a home this house to a home as well as this one here I'm still going to sort the students by name but I'm going to say that they're not in a house but rather from a home so I've just Chang the names of my variables in my grammar in English here ultimately to print out that for instance Harry is from number four privet drive and so forth but let's see what happens here when I run python of this version of students. having changed students. CSV to contain those homes and not houses enter huh our first value error like the program just doesn't work What might explain this value error the explanation of which rather cryptically is too many values to unpack and the line in question is this one involving split how did all of a sudden after all of these successful runs of this program did line five suddenly now break in the line in students that says we you have three values there's a line that you have three values and and students yeah I spent a lot of time trying to figure out where uh every student should be from so that we could create this problem for us and wonderfully like the first sentence of the book is number four privet drive and so the fact that that address has a comma in it is problematic why because you and I decided some time ago to just standardize on commas CSV comma separated values to denote the uh uh we standardized on commas in order to delineate one value from another and if we have commas grammatically in the student's home we're clearly confusing it as this special symbol and the split function is now for just Harry trying to split it into three values not just two and that's why there's too many values to unpack because we're only trying to assign two variables name and house now what could we do here well we could just change our approach for instance like one Paradigm that is not uncommon is to use something uh a little more um a little less common like a vertical bar so I could go in and change all of my commas to Vertical bars that too could eventually come back to bite Us in that if my file eventually has vertical bars somewhere it might still break so maybe that's not the best approach I could maybe do something like this I could escape the data as I've done in the past and maybe I could put quotes around any English string that itself contains a comma and that's fine I could do that but then my code students. py is going to have to change too because I can't just naively split on a comma Now I'm going to have to be smarter about it I'm going to have to take into account split only on the commas that are not inside of quotes and oh it's getting complicated fast and at this point you need to take a step back and consider you know what if we're having this problem odds are many other people before us have had this same problem it is incredibly common to store data in files it is incredibly common to use CSV files specifically and so you know what why don't we see if there's a library in Python that exists to read Andor write CSV files rather than reinvent a wheel so to speak let's see if we can write better code by standing on the shoulders of others who have come before us programmers passed and actually use their code to do the reading and writing of csvs so we can focus on the part of our problem that you and I care about so let's propose that we go back to our code here and see how we might use the CSV Library indeed within python there is a module called CSV the documentation for it is at this URL here in Python's official documentation but there's a few functions that are pretty readily accessible if we just Dive Right In and let me OS that we do this let me go back to my code here and instead of Reinventing this wheel and reading the file line by line and splitting on commas and dealing now with quotes and privet drives and so forth let's do this instead at the start of my program let me go up and import the CSV module let's use this library that someone else has written that's dealing with all of these Corner cases if you will I'm still going to give myself a list initially empty in which to store all these students but I'm going to change my Approach here now just a little bit when I open this file with width let me go in here and change this a little bit I'm going to go in here now and say this uh reader equals csvreader passing in file as input so it turns out if you read the documentation for the CSV module it comes with a function called reader whose purpose in life is to read a CSV file for you and figure out where are the commas where are the quotes where are all the the potential Corner cases and just deal with them for you you can override certain defaults or assumptions in case you're using not a comma but a pipe or something else but by default I think it's just going to work now how do I iterate over a reader and not the raw file itself it's almost the same the library allows you still to do this for each row in the reader so you're not iterating over the file directly now you're iterating over the reader which is again going to handle all of the parsing of comma in new lines and more for each row in the reader what am I going to do well at the moment I'm going to do this I'm going to append to my students list the following dictionary a dictionary that has a name whose value is the current Row's First Column and whose house or rather home now is the Row's second column now it's worth noting that the reader for each line in the file indeed returns to me a row but it returns to me a row that's a list which is to say say that the first element of that list is going to be the student's name as before the second element of that list is going to be the student's home uh as now before but if I want to access each of those elements remember that lists are zero indexed we start counting at zero and then one rather than one and then two so if I want to get at the student's name I use Row Bracket zero and if I want to get at the student's home I use Row Bracket one but in my four Loop we can do that same unpacking as before if I know this CSV is only going to have two columns I could even do this for name home in reader and now I don't need to use list notation I can unpack things all at once and say name here and home here the rest of my code can stay exactly the same because what am I doing now on line 8 I'm still constructing the same dictionary as before albeit for homes instead of houses and I'm grabbing those values now not from the file itself and my use of split but the reader and again what the reader is going to do is figure out where are those commas where are the quotes and just solve that problem for you so let me go now down to my terminal window and run python of students. and hit enter and now we see successfully sorted no less that Draco is from Mal for Manor Harry is from number four comma Private Drive and Ron is from the burrow questions now on this technique of using CSV reader from that CSV module which again is just getting us out of the business of reading each line our in Reading each of those commas and splitting so my question is related to something a bit bit in the past um I recognize that you are reading a file every time you well you we're we're assuming that we have the CSV file to hand already in this case um is it possible to make a file readable and writable so in in in in case if you want you could you could write stuff to the but then at the same time you could have another function that reads through the file and as changes to it as you go along a really good question and the short answer is yes however historically the mental model for a file is that of a cassette tape years ago not really in use anymore but cassette tapes are sequential whereby they start at the beginning and if you want to get to the end you kind of have to uh unwind the tape to get to that point the closest analog nowadays would be something like Netflix or any streaming service where there's a scrubber that you have to go left to right you can't just jump there or jump there you don't have Random Access so the problem with files if you want to read and write them you or some Library needs to keep track of where you are in the file so that if you're reading from the top and then you write at the bottom and you want to start reading again you seek back to the beginning so it's not something we'll do here in class it's more involved but it's absolutely doable for our purposes we'll generally recommend read the file and then if you want to change it write it back out rather than trying to make more peac mail changes which is good if the though the file is massive and it would just be very expensive TimeWise to change the whole thing other questions on this CSV reader is possible to write uh a paragraph in that file absolutely right now I'm writing very small strings just names or houses as I did before but you can absolutely write as much text as you want indeed other questions on CSV reader can user choose himself a key like input key will be a name or home so short answer yes we could absolutely write a program that prompts the user for a name and a home a name and a home and we could write out those values and in a moment we'll see how you can write to a CSV file for now I'm assuming as the programmer who created students. CSV that I know what the columns are going to be and therefore I'm naming my variables accordingly however this is a good seg way to one final feature of reading csvs which is that you don't have to rely on either getting a row as a list and using bracket zero or bracket one and you don't have to unpack things manually in this way we could actually be smarter and start storing the names of these columns in the CSV file itself and in fact if any of you have ever opened a spreadsheet file before be it in Excel Apple Numbers Google spreadsheets or the like odds are you've noticed that the first row very frequently is a little different it actually is boldface sometimes or it actually contains the names of those columns the names of those attributes below and we can do this here in students. CSV I don't have to just keep assuming that the student's name is first and that the student's home is second I can explicitly bake that information into the file just to reduce the probability of mistakes down the road I can literally use the first row of this file and say name comma home so notice that name is not literally something some 's name and home is not literally someone's home it is literally the words name and home separated by a comma and if I now go back into students. py and don't use CSV reader but instead I use a dictionary reader I can actually treat my CSV file even more flexibly not just for this but for other examples too let me do this instead of using a CSV reader let me use a CSV dict reader which will now iterate over the file top to bottom loading in each line of text not as a list of columns but as a dictionary of columns what's nice about this is that it's going to give me automatic access now to those columns names I'm going to revert to just saying for Row in reader and now I'm going to append a name and a home but how am I going to get access to the current rows name and the current rows home well earlier I used bracket zero for the first and bracket one for the second when I was using a reader a reader returns lists a dict reader or dictionary reader returns dictionaries one at a time and so if I want to access the current Row's name I can say row quote unquote name I can say here for home row quote unquote home and I now have access to those same values the only change I had to make to be clear was in my CSV file I had to include on the very first row little hints as to what these columns are and if I now run this code I think it's should behave pretty much the same python of students. and indeed we get the same sentences but now my code is more robust against changes in this data if I were to open the CSV file in Excel or Google spreadsheets or apple numbers and for whatever reason change the columns around maybe this is a file that you're sharing with someone else and just because they decide to sort things differently left or right by moving the columns around previously my code would have broken because I was assuming that name is always first and home is always second but if I did this be it manually in one of those programs or here home comma name and suppose I reversed all of this the home comes first followed by Harry the burrow then by Ron and then lastly Maloy Manor then Draco notice that my file is now completely flipped the First Column is now the second and the second's the first but I took care to update the header of that file the first row notice my python code I'm not going to going to touch it at all I'm going to rerun python of students. py and hit enter and it still just works and this too is an example of like coding defensively like what if someone changes your CSV file your data file ideally that won't happen but even if it does now because I'm using a dictionary reader that's going to infer from that first row for me what the columns are called my code just keeps working and so it keeps getting if you will better and better any questions now on this approach yeah what is the importance of new line CSV file what's the importance of the new line in the CSV file it's partly a convention in the world of text files we humans have just been for decades in the habit of storing um data line by line it's visually convenient it's just easy to extract from the file because you just look for the new lines so the new line just separates some data from some other data we could use any other symbol on the keyboard but it's just common to hit enter to just move the data to the next line just a convention other questions it seems to be working fine if you just have name and home I'm wondering what will happen if you want to put in more data um say you wanted to add the house to both the name and the home sure if you wanted to add the house back so if I go in here and add house last and I go here and say uh Gryffindor for Harry Gryffindor for Ron and Slither in for Draco now I have three columns effectively if you will home on the left name in the middle house on the right each separated by commas with weird things like number four comma privet Drive still quoted notice if I go back to students. py and I don't change the code at all and run python of students dopy it still just works and this is what's so powerful about a dictionary reader it can change over time it can have more and more columns your existing code is not going to break your code would break would be much more fragile so to speak if you were making assumptions like the first column's always going to be name the second column's always going to be house things will break fast if those assumptions break down so not a problem in this case well let me propose that besides reading csvs let's at least take a peek at how we might write a CSV too if you're writing a program in which you want to store not just students names but maybe their homes as well in a file how can we keep adding to this file let me go ahead and delete the contents of students. CSV and just read a single simple row name comma home so as to anticipate inserting more names and homes into this file and then let me go to students. py and let me just start fresh so as to write out data this time I'm still going to go ahead and import CSV I'm going to go ahead now and prompt the user for their name so input quote unquote what's your name question mark and I'm going to go ahead and prompt the user for their home so home equals input quote unquote where's your home question mark now I'm going to go ahead and open the file but this time for writing instead of reading as follows with open quote unquote students. CSV I'm going to open it in append mode so that I keep adding more and more students and homes to the file rather than just overwriting the entire file itself and I'm going to use a variable name of file I'm then going to go ahead and give myself a variable called writer and I'm going to set it equal to the return value of another function in the CSV module called CSV do writer and that writer uh function takes as its sole argument the file variable there now I'm going to go ahead and just do this I'm going to say writer. WR row and I'm going to pass into WR Row the line that I want to write to the file specifically as a list so I'm going to give this a list of name comma home which of course are the contents of those variables now I'm going to go ahead and save the file I'm going to go ahead and rerun python of students. hit enter and what's your name well let me go ahead and type in Harry as my name and number four comma Private Drive enter now notice that input itself did have a comma and so if I go to my CSV file now notice that it's automatically been quoted for me so that subsequent reads from this file don't confuse that comma with the actual comma between Harry and his home well let me go ahead and run it a couple of more times let me go ahead and rerun python of students. py let me go ahead and input this time Ron and his home as the burrow let's go back to students. CSV to see what it looks like now we see Ron comma the burough has been added automatically to the file and let's do one more python of students. enter let's go ahead and give draco's name and his home which would be Malfoy Manor enter and if we go back to students. CSV now we see that Draco is in the file itself and the library took care of not only writing each of those rows per the function name it also handled the escaping so to speak of any strings that themselves contained a comma like Harry's own home well it turns out there's yet another way we could implement this same program without having to worry about precisely that order again and again and just passing in a list it turns out if we're keeping track of what's the name and what's the home we could use something like a dictionary to associate those keys with those values so let me go ahead and back up and remove these students from the file leaving only the header row again name comma home and let me go over to students. py and this time instead of using CSV writer I'm going to go ahead and use CSV do dict writer which is a dictionary writer that's going to open the file in much the same way but rather than write a row as this list of name comma home what I'm now going to do is follows I'm going to first uh output an actual dictionary the first key of which is Name colon and then the value thereof is going to be the name that was typed in and I'm going to pass in a key of Home quote unquote the value of which of course is the home that was typed in but with dict writer I do need to give it a hint as to the order in which those columns are when writing it out so that subsequently they could be read even if those orderings change let me go ahead and pass in field names which is a second argument to dict writer equals and then a list of the actual columns that I know are in this file which of course are name comma home those times in quotes because that's indeed the string names of the column so to speak that I intend to write to in that file all right now let me go ahead and go to my terminal window run python of students. py this time I'll type in Harry's name again I'll again type in number four comma Private Drive enter let's now go back to students. CSV and voila Perry's back in the file and it's properly escaped or quoted I'm sure then if we do this again with Ron and the burrow and let's go ahead and run it one third time with Draco and Malfoy Manor enter let's go back to students. CSV and Via this dictionary writer we now have all three of those students as well so whereas with CSV writer the onus is on us to pass in a list of all of the values we want to put from left to right with a dictionary writer technically they could be in any order in the dictionary in fact I could just have correctly done this passing in home followed by name but it's a dictionary and so the ordering in this case does not matter so long as the key is there and the value is there and because I have passed in field names as the second argument to dict writer it ensures that the library knows exactly which column contains name or home respectively are there any questions now on dictionary reading dictionary writing or csvs more generally inia any specific specific situation for me to use single quotation or double quotation because uh after the print we use single quotation to represent the key of the dictionary but after the reading or writing we use the double quotation it's a a good question in Python you can generally use double quotes or you can use single quotes and it doesn't matter you should just be self-consistent so that stylistically your code looks the same all throughout sometimes though it is necessary to alternate if you're already using double quotes as I was earlier for a long f string but inside that F string I was interpolating the values of some variables using curly braces and those variables were dictionaries and in order to index into a dictionary you use square brackets and then quotes but if you're already using double quotes out here you should generally use single quotes here or vice versa but otherwise I'm in the habit of using double quotes everywhere others are in the habit of using single quotes everywhere it only matters sometimes if one might be confused for the other other questions on dictionary writing or reading uh yeah d uh my question is can we use multiple CSV files in any program absolutely you can use as many CSV files as you want and it's just one of the formats that you can use to save data other questions on csvs or file IO thanks for taking my question uh so when you're reading from the file the um you had the um uh as a as a dictionary you had the fields called um couldn't you just call when you're reading could couldn't you just call the row in the previous version of the of the students uh P file um when you're reading the uh when you're reading each row you are splitting out the um the fields by name yeah so when you're pending to the uh to the students list can you just call the uh for row and reader students. append row rather than uh rather than naming each of the fields oh very clever uh short answer yes in so far as dict reader returns one dictionary at a time when you Loop over it row is already going to be a dictionary so yes you could actually get away with doing this and the effect would really be the same in this case good observation how about one more question on csvs yeah uh when reading in csvs from my past work with data a lot of things can go wrong I don't know if it's a fair question that you can answer in a few sentences but are there any best practices to double check that sort of no mistakes occurred it's a really good question and I would say in general if you're using code to generate the csvs and to read the csvs and you're using a good Library theoretically nothing should go wrong it should be 100% correct if the libraries are 100% correct uh you and I tend to be the problem like when you let a human touch the CSV or when Excel or apple numbers or some other tools involve that might not be aligned with your codes expectations things then yes can break um the goal really sometimes honestly the solution is manual fixes you go in and fix the CSV or you have a lot of error checking or you have a lot of try except just to tolerate mistakes in the data but generally I would say if you're using CSV or any file format internally to a program to both read and write it you shouldn't have concerns there you and I the humans are the problem generally speaking and not the programmers the users of those files instead all right allow me to propose that we leave csvs behind but to note that they're not the only file format you can use in order to read or write data in fact they're a popular format as is just raw text files. txt files but you can store data really any way that you want we've just picked csvs because it's representative of how you might read and write from a file and do so in a structured way where you can somehow have multiple Keys multiple values all in the same file without having to resort to what would be otherwise known as a binary file so a binary file is a file that's really just zeros and ones and they can be laid out in any pattern you might want particularly if you want to store not textual information but maybe graphical or audio or video information as well so it turns out that python is really good when it comes to having libraries for really everything and in fact there's a popular Library called pillow that allows you to navigate image files as well and to perform operations on image files you can apply filters aot Instagram you can uh animate them as well and so what I thought we'd do is leave behind text files for now and Tackle one more demonstration this time focusing on uh this particular library and image files instead so let me propose that we go over here to VSS code and create a program ultimately that creates an anim GIF these things are everywhere nowadays in the form of memes and animations and stickers and the like and an animated gif is really just an image file that has multiple images inside of it and your computer or your phone shows you those images one after another sometimes on an endless loop again and again and so long as there's enough images it creates the illusion of Animation because your mind and mind kind of fills in the gaps visually and just assumes that if something is moving even though you're only seeing one frame per second or some sequence thereof it looks like an animation so it's like a simplistic version of a video file well let me propose that we start with maybe a couple of uh costumes from another popular programming language and let me go ahead and open up my first costume here number one so suppose here that this is a costume or really just a static image here costume 1.f and it's just a static picture of a cat no movement at all let me go ahead now and open up a second one costume 2.gif that looks a little bit different notice and I'll go back and forth this cat's legs are a little bit aligned differently so that this was version one and this was version two now these cats come from a programming language from MIT called scratch that allows you very graphically to animate all this and more but we'll use just these two static images costume one and costume 2 to create our own animated gif that after this you could text to a friend or message them um much like any meme online well let me propose that we create this animated gif not by just using some off-the-shelf program that we downloaded but by writing our own code let me go ahead and run code of costumes. and create our very own program that's going to take as input two or even more image files and then generate an animated gif from them by essentially creating this animated gif by toggling back and forth endlessly between those two images well how am I going to do this well let's assume that this will be a program called costumes. that expects uh two command line arguments the names of the files the individual costumes that we want to animate back and forth so to do that I'm going to import CIS so that we ultimately have access to cis.org V I'm then from this pillow Library going to import support for images specifically so from pil import image capital i as per the library's documentation now I'm going to give myself an empty list called images just so I have a list in which to store one or two or or more of these images and now let me do this for each argument in cy. argv I'm going to go ahead and create a new image variable set it equal to this image uh doop function passing in ARG now what is this doing I proposing that eventually I want to be able to run python of costumes. piy and then as command line argument specify costume 1.f space costume 2. so I want to take in those file names from the command line as my arguments so what am I doing here well I'm iterating over sis. argv all of the words in my command line arguments I'm creating a variable called image and I'm passing to this function image. open from the pillow library that specific argument and that library is essentially going to open that image in a way that gives me a lot of functionality for manipulating it like animating now I'm going to go ahead and uh pen to my images list that particular image and that's it so this Loop's purpose in life is just to iterate over the command line arguments and open those images using this Library the last line is pretty s straightforward I'm going to say this I'm going to grab the first of those images which is going to be in my list at location zero and I'm going to save it to disk that is I'm going to save this file now in the past when we use csvs or text files I had to do the file opening I had to do the file writing maybe even the closing I don't need to do that with this Library the pillow library takes care of the opening the closing and the saving for me by just calling save I'm going to call this save function and just to leave space because I have a number of arguments to pass I'm going to move to another line so it fits I'm going to pass in the name of the file that I want to create costume. GIF that will be the name of my animated gif I'm going to tell this library to save all of the frames that I passed to it so the First costume the second costume and even more if I gave them I'm going to then append to this first image the images zero uh the following images equals this list of images and this is a bit clever but I'm going to do this I want to append the next image there images one and now I want to specify a duration of 200 Mill seconds for each of these frames and I want this to Loop forever and if you specify Loop equals zero that is Time Zero it means it's just not going to Loop an finite number of times but an infinite number of times instead and I need to do do one other thing recall that sis. argv contains not just the words I typed after my program's name but what else does cy. argv contain if you think back to our discussion of command line arguments what else is in sis. RGV besides the words I'm about to type like costume 1.f and costume 2 yeah so we'll actually get in the the original name of the program we want to run the costume at p and we'll get the original name of the program costumes. in this case which is not a gif obviously so remember that using slices in Python we can do this if cy. Arvy is a list and we want to get a slice of that list everything after the first element we can do one colon which says start at location one not zero and take a slice all the way to the end so give me everything except the first thing in that list which to McKenzie's point is the name of the program now if I haven't made any mistakes let's see what happens I'm going to run python of costumes. piy and now I'm going to specify the two images that I want to animate so costume 1.f and costume 2.if what is the code now going to do well to recap we're using the Cy library to access those command line arguments we're using the pillow library to treat those files as images and with all the functionality that comes with that Library I'm using this images list just to accumulate all of these images one at a time from the command line and in lines 7 through n I'm just using a loop to iterate over all of them and just add them to this list after opening them with the library and the last step which is really just one line of code broken on to three so that it all fits I'm going to save the first image but I'm asking the library to append this other image to it as well not bracket zero but bracket one and if I had more I could express those as well I want to save all of these files together I want to pause 200 milliseconds a fifth of a second in between each frame and I want it to Loop infinitely many times so now if I cross my fingers as always hit enter nothing bad happened and that's almost always a good thing let me now run code of costumes. GIF to open up in VSS code the final image and what I think I should see is a very happy cat and indeed so now we've seen not only that we can read and write files be it textually we can read and now write files that are binary zeros and ones we've just scratched the surface this is using the library called pillow but ultimately this is going to give us the ability to read and write files however we want so we've now seen that via file.io we can manipulate not just textual files be it txt files or csvs but even binary files as well in this case they happen to be images but if we dived in deeper we could find explore audio and video and so much more all by way of these simple Primitives this ability somehow to read and write files that's that's it for now we'll see you next time [Music] [Music] all right this is cs50's Introduction to programming with python my name is David men and this is our week on regular Expressions so a regular expression otherwise known as a Rex is really just a pattern and indeed it's quite common in programming to want to use patterns to match on some kind of data often user input for instance if the user types in an email address whether to your program or a website or an app on your phone you might ideally want to be able to validate that they did indeed type in an email address and not something compl completely different so using regular Expressions we're going to have the new found capability to Define patterns in our code to compare them against data that we're receiving from someone else whether it's just a validated or heck even if we want to clean up a whole lot of data that itself might be messy because it too came from us humans before though we use these regular Expressions let me propose that we solve a few problems using just some simpler syntax and see what kind of limitations we run up against let me propose that I open up via code here and let me create a file called validate dopy the goal at hand being to validate how about just that a user's email address they've come to your app they've come to your website they type in their email address and we want to say yes or no this email address looks valid all right let me go ahead and type code of validate dopy to create a new tab here and then within this tab let me go ahead and start writing some code how about that keeps things simple initially first let me go ahead and prompt the user for their email address and I'll store return value of input in a variable called email asking them what's your email question mark I'm going to go ahead and preemptively at least clean up the user's input a little bit by minimally just calling strip at the end of my call to input because recall that input returns a string or a stir stirs come with some built-in methods or functions one of which is strip which has the effect of stripping off any leading white space to the left or any trailing white space to the right so that's just going to go ahead and at least avoid the human having accidentally typed in a space character we're going to throw it away just in case now I'm going to do something simple for a user's input to be an email address I think we can all agree that it's got to minimally have an at sign somewhere in it so let's start simple if the user has typed in something with an at sign let's very generously just say Okay valid looks like an email address and if we're missing that at sign let's say invalid because clearly it's not an email address it's not going to be the best version of my code yet but we'll start simple so I'm going to ask the question if there is an at symbol in the user's email address go ahead and print out for instance quote unquote valid else if there's not now I'm pretty confident that the email address is in fact invalid now what is this code doing well if at sign in email is a pythonic way of asking is this string quote unquote at in this other string email no matter where it is at the beginning the middle of the end it's going to automatically SE search through the entire string for you automatically I could do this more verbosely and I could use a for Loop or a while loop and look at every character in The user's email address looking to see if it's an at sign but this is one of the things that's nice about python you can do more with less so just by saying if at quote unquote in email we're achieving that same result we're going to get back true if it's somewhere in there thus valid or false if it is not well let me go ahead now and run this program in my terminal window with python of validate dopy and I'm going to go head and give it my email address maen harvard.edu enter and indeed it's valid looks valid is valid but of course this program is technically broken it's buggy what would be an example input if someone might like to volunteer and answer here that would be considered valid but you and I know it really isn't valid yeah thank you uh well for instance you can type just two science science and that's it and it still be valid still be valid according to your program but this exactly we've set a very low bar here in fact if I go ahead and rerun python of validate dopy and I'll just type in one at sign that's it no username no domain name this doesn't really look like an email address but unfortunately my code thinks it in fact is because it's obviously just looking for an at sign alone well how could we improve this well minimally an email address I I think tends to have though this is not actually a requirement tends to have an at sign and a single dot at least maybe somewhere in the domain name so mailin Harvard Dot edu so let's check for that dot as well though again strictly speaking doesn't even have to be that case but I'm going for my own email address at least for now as our test case so let me go ahead and change my code now and say not only if at is an email but also uh dot is an email as well so I'm asking now two questions I have two Boolean Expressions if at an email and I'm anding them together logically this is a logical and so to speak so if it's the case that at is an email and Dot is an email okay now I'm going to go ahead and say valid all right this would still seem to work for my email address let me go ahead and run python of validate dopy uh maen harvard.edu enter and that of course is valid as expected but here too we can be a little adversarial and type in something nonsensical like at Dot and unfortunately that too is going to be mistaken as valid even though there's still no username domain name or anything like that so I think we need to be a little more methodical here in fact notice that if if I do this like this uh the at sign can be anywhere and the dot can be anywhere but if I'm assuming the user is going to have a traditional domain name like harvard.edu or gmail.com I really want to look for the dot in the domain name only not necessarily just the username so let me go ahead and do this let me go ahead and introduce a bit more logic here and instead do this let me go ahead and do uh email.it of quote unquote at sign so email again is a string or a stir stirs come with methods not just strip but also another one called split that is the name applies will split one stir into multiple ones if you give it a character or more to split on so this is hopefully going to return to me two parts from a traditional email address the username and the domain name and it turns out I can unpack that sequence of respon is by doing this username comma domain equals this I could store it in a list or some other structure but if I already know in advance what kinds of values I'm expecting a username and hopefully a domain I'm going to go ahead and do it like this instead and just Define two variables at once on one line of code and now I'm going to be a little more precise if username uh uh if username then I'm going to go ahead and say print valid else I'm going to go ahead and say print invalid now this isn't good enough but I'm at least checking for the presence of a username now and you might not have seen this before but if you simply ask a question like if username and username is a string well usern if username is going to give me a true answer if username is anything except none or quote unquote nothing so there's a truthy value here whereby if username has at least one character that's going to be considered true but if username has no characters it's going to be considered a false value effectively but this isn't good enough I don't want to just check for username I want to also check that it's the case that dot is in the domain name as well so notice here there's a bit of potential confusion with the English language here I seem to be saying if username and Dot in domain as though I'm asking the question if the username and the dot are in the domain but that's not what this means these are two separate Boolean Expressions if username and separately if dot in domain and if I parenthesize this we could make that even more clear by putting parenthesis there parentheses here so just to be clear it's really two Boolean Expressions that we're anding together not one longer english-like sentence now if I go ahead and run this python of validate dopy enter I'll do my own email address again maen harvard.edu and that's valid and it looks like I could tolerate something like this if I do mailin at just say Harvard I think at the moment this is going to be invalid now maybe the top level domain Harvard exists but at the moment it looks like we're looking for something more we're looking for a top level domain too like edu so for now we'll just consider this to be invalid but it's not just that we want to do it's not just that we want to check for the presence of a username and the presence of a dot let's be more specific let's start to now narrow the scope of this program not just to be about generic emails more generally but about edu addresses so specifically for someone in a US University for instance whose email address tends to end with doedu I can be a little more precise and you might recall this function already instead of just saying is there a DOT somewhere in domain let me instead say and the domain ends with quote unquote. edu so now we're being even more precise we want there to be minimally a username that's not empty it's not just quote unquote nothing and we want the domain name to actually end with doedu let me go ahead and run python of validate dopy and just to make sure I haven't made things even worse let me at least chest my own email address which does seem to be valid now it seems that I minimally need to provide a username because we definitely do have that check in place so I'm going to go ahead and say Ma and now I'm going to go ahead and say at and it looks like I could be a little malicious here just say mailen at.edu as though minimally meeting the requirements of this of this pattern and that of course is considered valid but I'm pretty sure there's no one at mail at.edu we need to have some domain name in there so we're still not being quite as generous now we could absolutely continue to iter at on this program and we could add some more Boolean Expressions we could maybe use some other python methods for checking more precisely as there's something to the left of the dot to the right of the dot we could use split multiple times but honestly this just escalates quickly like you end up having to write a lot of code just to express something that's relatively simple in spirit just format this like an email address so how can we go about improving this well it turns out in Python there's a library for regular Expressions it's called ccin re and in the re Library you have a lot of capabilities to Define and check for and even replace patterns again a regular expression is a pattern and this Library the re library in Python is going to let us to Define some of these patterns like a pattern for an email address and then use some built-in functions to actually validate a user's input against that pattern or even use these patterns to change the user's input or extract partial information there from we'll see examples of all this and more so what can should I do with this Library well first and foremost it comes with a lot of functionality here is the URL for instance to the official documentation and let me propose that we focus on using one of the most versatile functions in the library library namely this search re. search is the name of the function in the re module that allows you to pass in a few arguments the first is going to be a pattern that you want to search for in for instance a string that came from a user the string arguments here is going to be the actual string that you want to search for that pattern and then there's a third argument optionally that's a whole bunch of flags a flag in general is like a a parameter you can pass in to modify the behavior of the function but initially we're not even going to use this we're just going to pass in a couple of arguments instead so let me go ahead and employ this re Library this regular expression library and just improve on this design incrementally so we're not going to solve this problem all at once but we'll take some incremental steps I'm going to go back to VSS code here and I'm going to go ahead now and get rid of most of this code but I'm going to go into the top of my file and first and all import this re Library so import re gives me access to that function and more now after I've gotten the user's input in the same way as before stripping off any leading or trailing whites space I'm just going to use this function super trivially for now even though this isn't really a big step forward I'm going to say if re. search contains quote unquote at in the email address then let's go ahead and print valid else let's go ahead and print invalid at the moment this is really no better than my very first version where I was just asking python if at sign in the email address but now I'm at least beginning to use this Library by using its own re. search function which for now you can assume returns a a True Value effectively if indeed the at sign is an email just to make sure that this version does work as I expect let me go ahead and run python of validate dopy and enter I'll type in in my actual email address and we're back in business but of course this is not great because if I similarly run this version of the program and just type in an at sign not an email address and yet my code of course thinks it is valid so how can I do better than this well we need a bit more vocabulary in the realm of regular expressions in order to be able to express ourselves a little more precisely really the pattern I want to ultimately Define is going to be something like I want there to be something to the left then an sign then something to the right and that something to the right should end with edu but should also have something before the edu like Harvard or Yale or any other school in the US as well well how can I go about doing this well it turns out that in the world of regular Expressions whether in python or a lot of other languages as well there's certain symbols that you can use to define patterns at the moment I've just used literal raw text if I go back to my code here this technically qualifies as a regular expression I've passed in a quoted string inside of which is an at sign now that's not a very interesting pattern it's just an at sign but it turns out that once you have access to regular expressions or a library that offers that feature you can more powerfully express yourself as follows let me reveal that the pattern that you passed to ar. search can take a whole bunch of special symbols and here's just some of them in the examples we're about to see in the patterns we're about to Define here are the special symbols you can use a single period a DOT to just represent any character except a new line a blank line so that is to say if I don't really care what letters of the alphabet are in the user's username I just want there to be one or more characters uh in the user's name dot allows me to express a through z uppercase and lowercase and a bunch of other letters as well star is going to mean in single asterisk zero or more repetitions so if I say something star that means that I'm willing to accept either zero repetitions that is nothing at all or more repetitions one or two or three or 300 if you see a plus in my patterns that's going to mean one or more repetitions that is to say there's got to be at least one character there one symbol and then there's optionally more after that and then you can say zero or one repetition you can use a single question mark after a symbol and that will say I want zero of this character or one but that's all I'll expect and then lastly there's going to be a to specify a specific number of symbols if you use these curly braces and a number represented here symbolically as M you can specify that you want M repetitions be it one or two or three or 300 you can specify the number of repetitions yourself and if you want a range of repetitions like you want this few characters or this many characters you can use curly braces and two numbers inside called here M and N which would be a range of M through n repetitions now what does all of this mean well let me go back to vs code here and let me propose that we iterate on this solution further it's not sufficient to just check for the at sign we know that already we minimally want something to the left and to the right so how can I represent that I don't really care what the user's username is or what letters of the alphabet are in it be it Ma or anyone else's so what I'm going to do to the left of this equal sign is I'm going to use a single period the dot that again indicates any character except for a new line but I don't just want a single character otherwise the P person username could only be a at such and such or B at such and such I want it to be multiple such characters so I'm going to initially use a star so dot star means give me something to the left and I'm going to do another one do star something to the right now this isn't perfect but it's at least a step forward because now what I'm going to go ahead and do is this I'm going to rerun python to validate dopy I'm going to keep testing my own email address just to make sure I haven't made things worse and that's now okay I'm now going to go ahead and type in some other input like how about just uh maen at with no domain name whatsoever and you would think this is going to be invalid but but but it's still considered valid but why is that if I go back to this chart why is maen at with no domain now considered valid what's my mistake here by having used doar at. Star as my regular expression or Rex because you're using the star instead of the plus sign exactly the star again means zero or more repetitions so r. search is perfectly happy to accept nothing after the equ after the at sign because that would be zero repetitions so I think I minimally need to evolve this and go back to my code here and let me go ahead and change this from Star to plus and let me change the ending from Star to plus so that now when I run my code here let me go ahead and run python of validate dopy I'm going to test my email address as always still working now let me go ahead and type in that same thing from before that was accidentally considered valid now I hit enter finally it's invalid so now we're making some progress on being a little more precise as to what it is we're doing now I'll note here like with almost everything in programming python included there's often multiple ways to solve the same problem and does anyone see away in my code here that I could make a slight tweak if I forgot that the plus operator exists and go back to using a star if I allowed you only to use dots and only Stars could you recreate the notion of plus yes um use another dot dot dot star yeah because if a DOT means any character we'll just use a DOT and then when you want to say or more use another Dot and then the star so equivalent to dot plus would have been dot dot star because the first dot means any character and the second pair of characters Dot star means zero or more other characters and to be clear it does not have to be the same character just by doing Dot or dot star does not mean your whole username needs to be a or AA or A AA or A A AA it can vary with each symbol it just means zero or more of any character back to back so I could do this on both the left and the right which one is better you know it depends I think uh an argument could be made that this is even more clear because it's obvious now that there's a DOT which means any character and then there's the dot star but if you're in the habit of doing this frequently one of the reasons things like the plus exist is just to consolidate your code into something a little more succinct and if you're familiar with seeing the plus now maybe this is more readable to you so again just like with python more generally you're going to often see different ways to express the same patterns and reasonable people might agree or disagree as to which way is better than another well let me propose to that we can think about both of these models a little more graphically if this looks a little cryptic to you let me go ahead and rewind to the previous incarnation of this regular expression which was just a single dot star this regular expression doar at dostar means what again it means zero or more characters followed by a literal at sign followed by zero or more other characters now when you pass this pattern in as an argument to re. search it's going to read it from left to right and then use it to try to match against the input email in this case that the user typed in now how is the computer how is r . search going to keep track of whether or not the user's email matches this pattern well it turns out that it's going to be using a machine of sorts implemented in software known as a finite State machine or more formally a non-deterministic finite automaton and the way it works if we depict this graphically is as follows the re. search function starts over here in a so-called start State that's the sort of condition in which it begins and then it's going to read the user's email address from left to right and it's going to decide whether or not to stay in this first state or transition to the next state so for instance in this first state as the user reading my email address mailin at harvard.edu it's going to follow this curved edge up and around to itself a reflexive Edge and it's labeled dot because dot again just means any character so as the function is reading my email address mailin at harvard.edu from left to right it's going to follow these transitions as follows m a l a n and then it's hopefully going to follow this transition to the second state because there's a literal at sign both in this machine as well as in my email address then it's going to try to read the rest of my address h a r v a d do du and that's it and then the computer's going to check did it end up in a an accept state a final State that's actually depicted here pictorially a little differently with double circles one inside of the other and that just means that if the computer finds itself in that second accept state after having read all of the users input it is indeed a valid email address if by some chance the machine somehow ended up stuck in that first state which does not have double circles and is therefore not an accept state the computer would conclude this is an invalid email address instead by contrast if we go back to my other version of the code where I instead had Plus on both the left and the right recall that re. search is going to use one of these St machines in order to decide from left to right whether or not to accept the user's input like me harbor. edu can we get from the start state so to speak to an accept state to decide Yep this was in fact meeting the pattern well let's propose that this non-deterministic finite automaton look like this instead we're going to start as before in the leftmost start State and we're going to necessarily consume one character per this first Edge which is labeled with a DOT to indicate that we can consume any one character like the m in maen harvard.edu then we can spend some time consuming more characters before the at sign so the a l a n then we can consume the at sign then we can consume at least one more character because recall that the Rex has dot plus this time and then we can consume even more characters if we want so if we first consume the H in harvard.edu that then leaves the a r v a r d and then Dot e du and now here too we're at the end of the story but we're in an accept state because that circle at the end has two circles total which means that if the computer if this function finds itself in that accept state after reading the entirety of the user's input it is too in fact a valid email address if by contrast we had gotten stuck in one of those other states unable to follow a transition one of those edges and therefore unable to make progress in the user's input from left to right then we would have to conclude that that email address is in fact invalid well how can we go upon improving this code further let me propose now that we check not only for a username and also something after the username like a domain name but minimally required that the string ends with doedu as well well I think I could do this fairly straightforward not only do I want there to be something after the at sign like the domain like Harvard I want the whole thing to end with edu but there's a little bit of danger here what have I done wrong by implementing my regular expression now in this way by using plus at. plus. edu what could go wrong with this version uh the dot is an dot means something else in this context where it means zero or more repetitions of a character which is why it will interpret it differently exactly even though I mean for it to mean literally doedu a period and then edu unfortunately in the world of regular expression dot means any character which means that this string could technically end in a edu or B edu or cedu and so forth but that's not in fact that I want so any instincts now as to how I could fix this problem and let me demonstrate the problem more clearly let me go ahead and run this code here let me go ahead and type in maen harvard.edu and as always this does in fact work but Watch What Happens here let me go ahead and do Ma at Harvard and then uh M at Harvard question mark edu enter that too is valid so I could put any character there and it's still going to be accepted but I don't want question mark edu I want edu literally any instincts then for how we can solve this problem here how can I get this new function re. search and a regular expression more generally to literally mean a dot might you think can you use the uh Escape character the backslash indeed the so-called Escape character which we've seen before for outside of the context of regular Expressions when we talked about new lines back sln was a way of telling the computer I want a new line but without actually literally hitting enter and moving the cursor yourself and you don't want a literal n on the screen so back sln was a way to escape n and convey that you want a new line it turns out regular Expressions use a similar technique to solve this problem here in fact let me go into my regular expression and before that final dot let me put a single backslash in the world of regular Expressions this is a so-called special special sequence and it indicates per this backslash and a single dot that I literally want to match on a DOT it's not that I want to match on any character and then edu I want to match on a DOT or a period edu but we don't want python to misinterpret this backslash is beginning a an escape sequence something special like backs slash n which even though we as the programmer might type two characters backs slash n it really is interpreted by python as a single new line we don't want any kind of misinterpretation like that here so it turns out there's one other thing we should do for regular expressions like this that have a backslash used in this way I want to specify to python that I want this string this regular expression in double quotes to be treated as a raw string literally putting an r at the beginning of the string to indicate to python that you should not try to interpret any backslashes in the usual way I want to literally pass the backslash and the dot and the edu into this particular function search in this case so it's similar in spirit to using that f at the beginning of a format string which of course tells python to format the string in a certain way plugging in variables that might be between curly braces but in this case r indicates a raw string that I want passed in exactly as is now it's only strictly necessary if you are in fact using backslashes to indicate that you want some special sequence like backs slash dot but in general it's probably a good habit to get into to just use raw strings for all of your regular Expressions so that if you eventually go back in make a change make an addition you don't accident acally introduce a backslash and then forget that that might have some special or misinterpreted meaning well let me go ahead and try this new regular expression I'll clear my terminal window run python of validate run python of validate dopy and then I'll type in my email address correctly mailen harvard.edu and that's fortunately still valid Let Me Clear My screen and run it one more time python of validate dopie and this time let's mistype it as mailen Harvard questionmark edu where by there's obviously not a DOT there but there is some other Single Character that last time was misinterpreted as valid but this time now that I've improved my regular expression it's discovered as indeed invalid any questions now on this technique for matching something to the left of the at sign something to the right and now ending with edu explicitly um what happens when that a good question and you kind of called me out here well when in doubt let's try let me go ahead and do python validate dopy mailin harvard.edu which ALS so is incorrect unfortunately my code thinks it's valid so another problem to solve but a shortcoming for now other questions on these regular Expressions thus far can you use curly brackets M instead of back can you use curly brackets instead of backslash not in this case if you want a literal dot backslash Dot is the way to do it literally how about one other question on regular Expressions is this the same thing that Google forms uses in order to categorize data in let's say some if you've got multiple people sending in requests about some feedback do they categorize the data that they get using this particular regular expression thing indeed if you've ever used Google forms to not just submit it but to create a Google form one of the menu options is for response validation in English at least and what that allows you to do is specify that the user has to input an email address or a URL uh or a string of some length but there's an even more powerful feature that some of you may not have ever noticed and indeed if you'd like to open up Google forms create a new form temporarily and poke around you will actually see in English at least quote unquote regular expression mentioned as one of the mechanisms you can use to validate your users's input into your Google form so in fact after today you can start avoiding these specific dropdowns of like email address or URL or the like and you can express your own patterns precisely as well regular Expressions can even be used in VSS code itself if you go and find or do a find and replace in VSS code you can of course just type in words like you could into Microsoft Word or Google Docs you can also type if you check the right box regular expressions and start searching for patterns not literally specific values well let me propose that we now enhance this implementation further by introducing a few other symbols because right now with my code I keep saying that I want my email address to end with edu and start with a username but I'm being a little too generous this does in fact work as expected for my own email address maen harvard.edu but what if I type in a sentence like my email address is maen harvard.edu and suppose I've typed that into the program or I've typed that into a Google form is this going to be considered valid or invalid well let's consider it's got the at sign so we're good there it's got one or more characters to the left of the at sign it's got one or more characters to the right of the at sign it's got a literal doedu somewhere in there to the right of the at sign and granted there's more stuff to the right there's literally this period at the end of my English sentence but that's okay because at the moment my expression is not so precise as to say the pattern must start with the username and end with the doedu technically it's left unsaid what more can be to the left and what more can be to the right so when I hit enter now you'll see that that whole sentence in English is valid and that's obviously not what you want in fact consider the case of using Google forms or Office 365 to collect data from users if you don't validate your input your users might very well type in a full sentence or some else with a typographic IAL error not an actual email so if you're just trying to copy all of the results that have been typed into your form so you can paste them into Gmail or some email program it's going to break because you're going to accidentally paste something like a whole English sentence into the program instead of just an email address which is what your mailer expects so how can I be more precise well let me propose we introduce a few more symbols as well it turns out in the context of a regular expression one of these patterns you can use the carrot symbol the little triangular Mark to repres presentent that you want this pattern to match the start of the string specifically not anywhere but the start of the user string by contrast you can use a dollar sign in your regular expression to say that you want to match the end of the string or technically just before the new line at the end of the string but for all intents and purposes think of carrot as meaning start of the string and dollar sign as meaning end of the string it is a weird thing that one is a carrot and one is a dollar sign these are not really things that I think of as opposites like a parenthesis or something like that but those are the symbols the world chose many years ago so let me go back to VSS code now and let me add this feature to my code here let me specify that yes I do want to search for this pattern but I want the user's input to start with this pattern and end with this pattern so even though it's going to start looking even more cryptic I put a carrot symbol here at the beginning and I put a dollar sign here at the end that does not mean I want the user to type a carrot symbol or a dollar sign this is special symbology that indicates to re. search that it should only look for now an exact match against this pattern so if I now go back to my terminal window and I'll leave the previous result on the screen let me type the exact same thing my email address is ma at harvard.edu enter sorry period and now I'm going to go ahead and hit enter now that's considered invalid but let me clear the screen and just to make sure I didn't break things let me type in just my email address and that two is valid any questions now on this version of my regular expression which note goes further to specify even more precisely that I want it to match at the start and the end any questions on this one here okay you have slash and do edu and then the dollar sign but the dot is like one of the regular expression right it normally is but this backslash that I Deli put before this period here is an escape character it is a way of telling re. search that I don't want any character there I literally want a period there and it's the only way you can distinguish one from the other if I got rid of that slash this would mean that the email address just has to end with any character then an e then a d then a u i don't want that I want literally a period Then the E then the D then the U this is actually common convention in programming and technology in general if you and I decide on a convention whereby we're using some character on the keyboard to mean something special invariably we create a future problem for oursel when we want to literally use that same character and so the solution in general to that problem is to somehow escape the character so that it's clear to the computer that it's not that special symbol it's literally the symbol it sees so we don't even love it we don't need another another slash before the dollar sign no uh because in this case dollar sign means something special per this chart here dollar sign by itself does not mean US dollars or currency it literally means match the end of the string if however I wanted the user to literally type in a dollar sign at the end of their input the solution would be the same I would put a backslash before the dollar sign which means my email address would have to be something like mait harvard.edu dollar sign which is obviously not correct too so back slashes just allow you to tell the computer to not treat those symbols specially like meaning something special but to treat them literally instead how about one other question here on regular Expressions you said you said one represents to to make it one plus then you say one was to make it one with nothing sure so let me rewind in time I think what you're referring to was one of our earlier versions that initially looked like this which just meant Zero or more characters then an at sign than zero or more other characters we then evolved that to be this Plus on both sides which means one or more characters on the left then an at sign then one or more characters on the right and if I'm interpreting your question correctly one of the points I made earlier was that if you didn't use Plus or forgot that it exists you could equivalently achieve the exact same result with two dots and a star because the first dot means any character it's got to be there the second dot star means zero or more other characters and same on the right so it's just another way of expressing the same idea one or more can be represented like this with do do star or you can just use the handier syntax of plus which means the same thing all right so I dare say there's still some problems with the regular expression in this current form because even though now we're starting to look for the username at the beginning of the string from the user and we're looking for the edu literally at the end of the string from the user those dots are a little too encompassing right now I am allowed to type in more than the single at sign why because at is a character and Dot means any character so honestly I can have as many at signs as this thing at the moment as I want for instance if I run python of validate dopy mailin harvard.edu still works as expected but if I also run python to validate dopy and incorrectly do maen harvard.edu that should be invalid but it's considered valid instead so I I think we need to be a little more restrictive when it comes to that dot and we can't just say oh any old character there is fine we need to be more specific well it turns out that regular Expressions also support this syntax you can use square brackets inside of your pattern and inside of those square brackets include one or more characters that you want to look for specifically alternatively you can inside of those square brackets put a car symbol which unfortunately in this context means something completely different from match the start of the string but this would be the compliment operator inside of these square brackets which means you cannot match any of these characters so things are about to look even more cryptic now but that's why we're focusing on regular Expressions on their own here if I don't want to allow any character which is what a DOT is let me go ahead and I could just say well I only want to support a or B's or C's or D's or E's or FS or G's I could type in the whole alphabet here plus some numbers to actually include all of the letters that I do want to allow but honestly a little simpler would be this I could use a carrot symbol and then an at sign which has the effect of saying this is the set of characters that has everything except an at sign and I can do the same thing over here instead of a DOT to the right of the at sign I can do Open Bracket carrot at sign and I admit things are starting to escalate quickly here but let's start from the left and go to the right this carrot outside of the square brackets at the very start of my string as before means match from the start of the string and let's Jump Ahead the dollar sign all the way at the end of the regular expression means match at the end of the string so if we can mentally tick those off as straightforward let's now focus on everything else in the middle well to the left here we have new syntax a square bracket another carrot an at sign and a Clos square bracket and then a plus the plus means the same thing as always it means one or more of the things to the left what is the thing to the left well this is the new syntax inside of square brackets here I have a carrot symbol and then an at sign that just means any character except an at sign it's a weird syntax but this is how we can express that simple idea any character on the keyboard EX except for an at sign and heck even other characters that aren't physically on your keyboard but that nonetheless exist then we have a literal at sign then we have another one of these same things square bracket carrot at close bracket which means any character except an at sign then one or more of those things followed by literally a period U so now let me go ahead and do this again let me rerun python of validate dopy and test my own email address to make sure I've not made things work and we're good now let me go ahead and clear my screen and run python of validate dopy again and do mailin harvard.edu crossing my fingers this time and finally this now is invalid why I'm allowing myself to have one at sign in the middle of the user's input but everything to the left per this new syntax cannot be an at sign it can be anything but one or more times and everything to the right of the at sign can be anything but an at sign one or more time followed by lastly a literal. edu so again the new syntax is quite simply this square brackets allow you to specify a set of characters that you literally type out at your keyboard a bcde e f or the complement the opposite the carrot symbol which means not and then the one or more symbols you want to exclude questions now on this syntax here so right after add sign can we use the curly brackets M uh one so that we can only have one repetition of the ad symbol absolutely so we could do this let me go ahead and pull a VSS code and let me delete the current form of a regular expression and go back to where we began which was justar at and star I could absolutely do something like this and require that I want at least one of any character here and then I could do something more to have any more as well so the curly brace syntax which we saw on the slide earlier but didn't yet use absolutely can be used to specify a specific number of characters but honestly this is more verbose than is necessary the best solution arguably or the simplest at least ultimately is just to say do plus but there too another example of how you can solve the same problem multiple ways let me go back to where the regular expression just was and take other questions as well questions on these sets of characters or complimenting that set so can you use that same syntax to say that you don't want a certain character throughout the whole stream you could it's going to be uh you could absolutely use the same character to exclude a um you could absolutely use the syntax to exclude a certain character from the entire string but it would be a little harder right now because we're still requiring edu at the end but yes absolutely other questions what happens if the user inputs edu in the beginning of the thinging a good question what happens if the user types in doedu the beginning of the screen well let me go back to VSS code here and let's try to solve this in two different ways first let's look at the regular expression and see if we can infer if that's going to be tolerated well according to the current cryptic regular expression I'm saying that you can have any character except the at sign so that would work I could have the dot for the edu but then I have to have an at sign so that wouldn't really work because if I'm just typing in.edu we're not going to pass that constraint so now let me try this in uh by running the program let me type in just literally doedu that doesn't work but but but I could do this doedu at.edu that too is invalid but let me do this uhedu at something. edu that passes so it's starting to get a little weird now maybe it's valid maybe it's not but I think we'll eventually be more precise too how about one more question on this regular expression and these complimenting of sets can we use uh another domain name as a string input can you use another domain name absolutely I'm using my own just for the sake of demonstration but you could absolutely use any domain or top level domain and I'm using doedu which is very us-centric but this would absolutely work exactly the same for any top level domain all right let me go ahead now and propose that we improve this regular expression further because if I pull it up again in V vs code here you'll see that I'm being a little too tolerant still it turns out that there are certain requirements for someone's username and domain name in an email address there is an official standard in the world for what an email address can be and what characters can be in it and this is way to accommodating of all the characters in the world except for the at symbol so let's actually narrow the definition of what we're going to tolerate in usernames and companies like Gmail could certainly do this as well suppose that it's not just that I want to exclude at sign suppose that I only want to allow for say characters that normally appear in words like letters of the alphabet A through Z be it uppercase or lowercase maybe some numbers in heck maybe even an underscore could be allowed too well we can use this same square bracket syntax to specify a set of characters as follows I could do a b c d e f g h i j oh my God this is going to take forever I'm going to have to type out all 26 letters of the alphabet both lowercase and uppercase so let me stop doing that there's a better way already if you want to specify Within These square brackets a range of letters you can actually just do a hyphen if you literally do a hyphen Z in these square brackets the computer is going to know you mean a thusy you do not need to type 26 letters of the alphabet if you want to include uppercase letters as well you just do the same no spaces no commas you literally just keep typing a through capital Z so I have little a hyphen little Z big a hyphen big Z no spaces no commas no separators you just keep specifying those ranges if I additionally want numbers I could do 0 1 2 3 4 NOP you don't need to type in all 10 decimal digits you can just say 0 through n using a hyphen as well and if you now want to support underscores as well which is pretty common in usernames for email addresses you can literally just type in underscore at the at the end notice that all of these characters are in inside of square brackets which just again means here is a set of characters that I want to allow I have not used a carrot symbol at the beginning of this whole thing because I don't want to complement it complement it with an E not complement it with an i I want don't want to complement it by making it the opposite I literally want to accept only these characters I'm going to go ahead and do the same thing on the right if I want to require that the domain name similarly come from this set of characters which admittedly is a little too narrow but it's familiar for now so we'll keep it simple I'm going to go ahead and paste that exact same set of characters over there to the right and so now it's much more restrictive now I'm going to go ahead and run python of validate I'm going to test my own email address and we're still good I'm going to clear my screen and run it once more this time trying to break it let me go ahead and do something like how about davidor maen harvard. e do you enter but that too is going to be valid but if I do something completely wrong again like ma harvard.edu that's still going to be invalid why because my regular expression currently only allows for a single at in the middle because everything to the left must be alpha numeric alphabetical or numeric or an underscore the same thing to the right followed by the edu now honestly this is a regular expression that you might be in the habit of typing in the real world as in as cryptic as this might look this is the world of regular Expressions so you'll get more comfortable with this syntax over time but thankfully some of these patterns are so common that there are builtin shortcuts for representing some of the same information that is to say you don't have to constantly type out all of the symbols that you want to include because odds are some other programmer has had the same problem so built into regular Expressions themselves are some additional patterns you use and in fact I can go ahead and get rid of this entire set a through z lowercase A through Z uppercase 0 through 9 and an underscore and just replace it with a single back slw back slw in this case represents a word character which is commonly known as a alpha numeric symbol or the underscore as well I'm going to do the same thing over here I'm going to highlight the entire set of square brackets delete it and replace it with a single backs slash W and now I feel like we're making progress because even though it's cryptic and what if it looked way cryptic a little bit ago um and even though it would have looked even more cryptic a little bit ago now it's at least starting to read a little more friendly the carrot on the left means start matching at the beginning of the string back slw means any word character the plus means one or more at symbol literally then another word character one or more then a literal dot then literally EDU U and then match at the very end of the string and that's it so there's more of these two and we won't use them all here but here is a partial list of the patterns you can use within a regular expression one you have back SL D for any decimal digit decimal digit meaning 0 through n commonly done here too is if you want to do the opposite of that the complement so to speak you can do back slash capital D which is anything that's not a decimal digit so it might be letter and punctuation and other symbols as well Meanwhile Back SLS means Whit space characters like a single hit of the space or maybe hitting tab on the keyboard that's whites space back slash capital S is the opposite or complement of that anything that's not a whit space character back slw we've seen a word character as well as numbers and the underscore and if you want the complement or opposite of that you can use back SL capital W to give you everything but a word character again these are just common patterns that so many people were presumably using in yester year that it's now baked into the regular expression syntax so that you can more succinctly express your same ideas any questions then on this approach here where we're now using backw to represent my word character uh so what I want to ask about uh was the uh actually the previous approach like the square bracket approach could we accept like uh lists in there yes we'll see this before long but suppose you wanted to tolerate not just edu but maybe edu or do you could do this you could introduce parentheses and then you can or those together I could say Comm or edu I could also add in something like in the US or gov or net or anything else or org or the like and each of the vertical bars here means something special it means or and the parentheses simply group things together formally you have this syntax here A or B A or vertical Bar B means a has to match or B has to match where A and B can be any other patterns you want in parentheses you can group those things together so just like math you can uh combine ideas into one phrase and do this thing or the other um and there's other syntax as well that we'll soon see other questions on these regular expressions in this syntax here what if we put spaces in the expression sure so if you want spaces in there you can't use back slw alone because that is only a word character which is alphabetical numerical or the underscore but you could do this you could go back to this approach whereby you use uh square brackets and you could say A through Z or a through z or 0 through n or underscore or I'm going to hit the space bar a single space you can put a literal space inside of the square brackets which will allow you then to detect a space alternatively I could still use back slw but I could combine it as follows I could say give me a back slw or a back SL s because recall that back SLS is wh space so it's even more than a single space it could be a tab but by putting those things in parentheses now you can match either the thing on the left or the thing on the right one or more times how about one other question on these regular Expressions perfect so I was going to ask um does the back slw um include a DOT uh because no nope it only includes letters numbers uh and underscore that is it and I was wondering you gave an example at the beginning that had uh spaces like this is my email so on so um I don't think our current version even quite quite a long while ago stopped accepting it was that because of the carrot uh or because of something no the reason I was handling spaces and other English words when I typed out my email address is mailing at doedu was because we were using initially star or plus which is any character uh and even after that we said anything except the at sign which includes spaces only once I started using square brackets and a through z and 0 through 9 and underscore did we finally get to the point where we would reject whitespace and in fact I can run this here let me go into the current version of my code in VSS code which is using again the back slw's for word characters let me run python of validate and incorrectly type in something like my email address is mailen harvard.edu period which has spaces to the left of my username and that is now invalid because space is not a word character yorgo notes too that technically I'm not allowing dots and some of you might be thinking wait a minute my gmail address has a dot in it that's something we're going to still have to fix a back slw is not the end all here it's just allowing us to express our previous solution a little more succinctly now one thing we're still not handling quite properly is uppercase versus lowercase the back slw technically does handle lowercase letters and uppercase because it's the exact same thing as that set from before which had little a through little Z and big a through big Z but watch this let me go ahead in my current form run python to validate dopy and just because my caps slot key is down maen harvard.edu shouting my email address it's going to be okay in terms of the ma it's going to be okay in terms of the Harvard because those are matching the back slw which does include lowercase and uppercase but I'm about to see invalid why why is mailing at harvard.edu invalid when it's in all caps here even though I'm using backw yeah so you are asking for the domain. edu in lowercase and you're typing it in an uppercase exactly I'm typing in my email address in all uppercase but I'm looking for literally edu and as I see you with airpods and so many of you with headphones I apologize for yelling into my microphone just now to make this point but let's see if we can't fix that well if my pattern on line five is expecting it to be lowercase there's actually a few ways I can solve this one would be something we've seen before I could just force the user's input to all lowercase and I could put on the end of my first line lower and actually force it all to lowercase alternatively I could do that a little later instead of passing an email I could pass in the lowercase version of email because email addresses should in fact be case insensitive so that would work too but there's another mechanism here which is worth seeing it turns out that that function before called re. search supports recall a third argument as well these so-called flags and flags are configuration options typically to a function that allow you to configure it a little differently and how might I go about configuring this call to re. search a little bit differently in so far as I'm currently only passing in two arguments well it turns out that some of the flags you can pass into this function are these it turns out that the regular expression library in Python AKA re comes with a few built-in variables so to speak things that you can think of as constants that have meaning to re. search and they do so as follows if you pass in as a flag re. ignore case what re. search is going to do is ignore the case of the user's input it can be uppercase lower case a combination thereof the case is going to be ignored it will be treated case insensitively and you can do other things too that we won't do here but if you want to handle the user's input that maybe spans multiple lines maybe they didn't just type in an email address but an entire paragraph of text and you want to match different lines of that text that is multiple lines another flag is for re multi-line for just that or re doall whereby you can con uh you can configure the dot to rep to recognize not just any character except new lines but any character plus new lines as well but for now let me go ahead and just make use of this first one let me pass in a third argument to re. search which is re. uh ignore case let me now reun the program without clearing my screen python of validate dopy let me type in again in all caps effective ly shouting ma harvard.edu enter and now it's considered valid because I'm telling re. search specifically to ignore the case of the input and that two here is fine and why might I do this approach rather than call do lower in one of those other locations if I don't actually want to change the user's input for whatever reason I can still treat it case insensitively without actually changing the value of that variable itself are any final questions now on this validation of email addresses uh so the pattern is a string right M uh can we use an F string you can you yes you can use an F string so that you could plug in for instance the value of a variable and pass it into the function other questions on this access W character could we take it as an input from the user technically yes that's not a problem we're trying to solve right now we want the user to provide literal input like their email address not necessarily a regular expression but you could imagine building software that asks the user especially if they're more advanced users to type in a regular expression for some reason to validate something else against that and in fact that's what Google's doing if you play around with Google forms and create a form with response validation and select regular expression Google lets you and I type in our own regular Expressions would be a per which would be a perfect example of that all right well let me propose that we try to solve one other problem here whereby if I go into the same version as before which is now ignoring case but I type in one of my other email addresses let me go ahead and run python of validate dopy and this time let me type in not mailen harvard.edu which I use primarily but my another email address of mine maen cs50.h harvard.edu which forwards to the same let me go ahead and hit enter now and huh invalid even though I'm pretty sure that is in fact my email address well let's put our finger on the reason why why at the moment is mail at cs50.h harvard. edu being considered invalid even though I'm pretty sure I send and receive email from that address too why might that be because there is a DOT that has come after the ad symbol exactly there's a DOT after my cs50 and I'm not expecting any dots there I'm expecting only again word characters which is a through z 0-9 and under score so I'm going to have to retool here but how could I go about doing this well it turns out theoretically there could be other email addresses even though they'd be getting a little excessively long for instance mailin at something. cs50.h harvard.edu which is not technically exist but it could you can have of course multiple dots in a domain name like we see here wouldn't it be nice if we could handle that as well well let me propose that we modify my regular expression as follows it turns out that you can group ideas together and you can not only ask whether or not this pattern matches or this one using syntax like a vertical Bar B which means either A or B you can also group things together and then apply some other operator to them as well in fact let me go back to VSS code here and let me propose that if I want to tolerate a subdomain like cs50 that may or may not be there let me go ahead and change it as follows I could naively do this if I want to support subdomain I could say well let's allow for otherw characters plus and then a literal Dot and notice I'll highlight in blue here what I've just added everything else is the same but I'm now adding room for another sequence of one or more word characters and then a literal dot so this now I think if I rerun python of validate dopy will work for Ma at cs50.h harvard.edu enter unfortunately does anyone see where this is going let me rerun python of validate dopy and type in as I keep doing maen harvard.edu which up until now has kept working despite all of my changes but now finally I've broken my own email address so logically what's the solution here well there's a bunch of ways we could solve this I could maybe start using two regular expressions and support you uh email addresses of the form username at domain. TLD or username at subdomain dodoma TLD where TLD just means top level domain like edu or I could maybe just modify this one because I'd prefer not to have like two uh regular expressions or one that's twice as big why don't I just specify to re. search that part of this pattern is optional what was the symbol we saw earlier that allows you to specify that the thing before it is technically optional the straight bar we are using the Straight bar as a optional make the opt the argument optional so we could we could use a vertical bar and some parentheses and say either there's something here or there's nothing we could do that in parenthesis but I think there's actually an even easier way uh actually is a question mark indeed question mark think back to this summary here of our first set of symbols whereby we had not just Dot and star and plus but also a question mark which means literally zero or one repetitions which affect ly means optional it's either there one or it's not zero now how can I translate to that to this code here well let me go ahead and Surround this part of my pattern with parentheses which doesn't mean I want literally a parenthesis in the user's input I just want to group these characters together and in fact this now will still work I've only added parentheses around the new part for the subdomain let me run python of validate dopy let me run maen cs50.h harvard.edu enter that's still valid but to be clear if I rerun it again for ma harvard.edu that is still invalid but not if I go in here and say after the parentheses which now is one logical unit it's one big group of ideas together I add a single question mark there this will now tell re. search that that whole thing in parentheses can either be there once or be there not at all zero times so what does this translate into when I run it well let me go ahead and rerun it with maen cs50.h harvard.edu so that the subdomain is there that works as before let me clear my screen and run it again python of validate dopy with ma harvard.edu which used to work then broke is are we back in business now we are that's now valid again questions now on this approach where we've use not just the question mark But the parenthesis as well okay yeah you works for zero or one repetition what if you have more what if you have more that's okay that's where you could do star star is zero or more which gives you all the flexibility in the world yeah so I was just asking that uh uh with question mark there's only one repetition allow it means zero or one repetition so it's either not there or it is there and so that's why this pattern now if I go back to my code even though again it admittedly looks cryptic let me highlight everything after the at sign and before the dollar sign this now represents a domain name like harvard.edu or a subdomain within the domain name why well this part to the right is the same as always backw plus means something like Harvard or Yale back.edu means literally doedu so the new part is this in parentheses I have another set of back w+ back SL do now but it's all in parentheses I'm now having a question mark right after that which means that whole thing in parenthesis either can be there or it can't be there it's either of those that are acceptable so a question mark effectively make something optional it would not be correct to remove the parentheses because what would this mean if I remove the parentheses that would mean that only this dot is optional which isn't really what we want to express I want the subdomain like cs50 and the additional dot to be what's there or not there how about one other question on Rex is here can they use this for the usernames absolutely we still have other problems right we're not solving all of the problems today just yet but absolutely right now we are not letting you have a period in your username and again some of you with Gmail accounts or other accounts you probably have not just underscores numbers and letters you might have periods too well we could fix that not using question mark here per se but now that we have these parentheses at our disposal what I could do is this I could use parentheses to surround the back slw to say any word character which is the same thing again as a letter or a number or an underscore but I could also or in using a vertical bar something else like a literal dot now a literal dot needs to be escaped otherwise it represents any character which would be a regression a step back but now notice what I've done in parentheses I'm telling re. search that those first few characters in your email address that is your username has to be a word character Like A through Z uppercase or lowercase or 0 through n or an underscore or a literal dot we could do this differently too I could get rid of the parentheses and the or and I could just use a set of characters I could again manually say a through z a through z 0 through 9 underscore and then I could do a literal dot with a back slash period and now I technically don't even need the uppercase because I'm already telling the computer to ignore case I can just pick one or the other which one is better is really up to you whichever one you think is more readable would generally be the better design all right let me propose that I rewind this in time to where we left off which was here and let me propose that there are indeed still limitations of this solution not just with the username not just with the domain name we're still being a little too restrictive so would you like to see the official regular expression that at least browsers use nowadays whenever you type in an email address to a web form and the web form the browser tells you yes or no your email address is syntactically valid ready ready here is and this isn't even officially the right regular expression it's a simplified version that browsers use because it catches most mistakes but not all here we go this is the regular expression for a valid email address at least as browsers nowadays Implement them now it's crazy cryptic at first glance but not and it's wrapping onto many lines but it's just one pattern but just notice the now familiar symbols there is the carrot symbol at the very top there is the dollar sign at the very end there is a square bracket over here and then some of these ranges plus other characters turns out you don't normally see these characters in email addresses it looks like you're swearing at someone in their username but they're valid characters they're valid officially that doesn't mean that Gmail is going to allow you to put dollar signs and other punctuation in your username but officially some servers might allow that so if you really want to validate a user's email address you would actually come up with or copy paste something like this but honestly this looks so cryptic and if you were to type it out manually you are so likely to make a mistake what's the better solution here instead this is where P past week's libraries are your friend surely someone else on the internet a programmer more experienced than you even has come up with code that validates email addresses properly using this regular expression or even something more sophisticated than that so generally if the problem at hand is to validate input that is pretty conventional an email address a URL something where there's an official definition that's independent of you yourself find a the popular library that you're comfortable using and use it in your code to validate email addresses this is not a wheel necessarily that you yourself should invent we've used email addresses though to iteratively start from something simple too simple and build on top of that so you could certainly imagine using regular Expressions still to validate things that aren't email addresses but are data that are important to you so we at least now have these building blocks now besides the regular Expressions themselves it turns out there's other functions and Python's re library for regular Expressions among them is this function here re. match which is actually very similar to re. search except you don't have to specify the carrot symbol at the very beginning of your Rex if you want a match from the start of a string re. match by Design will automatically start matching from the start of the string for you similar in spirit is re. full match which does the same thing but not only matches at the start of the string but the end of the string so that you too don't need to type in the carrot symbol or the dollar sign as well but let's go ahead and transition back now to some actual code whereby we solve a different problem in spirit rather than just validate the users's input and make sure it looks the way we want let's just assume that the users are not going to type in data exactly as we want and so we're going to have to clean up their input this happens so often when you're using like a Google form or Office 365 form or anything else to collect user input no matter what your form question says your users are not necessarily going to follow those directions they might go ahead and type in something that's a little differently formatted than you might like now you could certainly go through the results and download a CSV or open the Google spreadsheet or equivalent in Excel and just clean up all the data manually but if you've got lots of submissions dozens hundreds thousands of rows in your data set doing things manually might not be very fun it might be much more effective to write code as in Python that can allow you to clean up that data and any future data as well so let me propose that we go ahead here and close validate dopy and let's go ahead and create a new program Al together called format. the goal of which is to reformat the user's input in the format we expect I'm going to go ahead and run code of format. py and let's suppose that the data we're going to reformat is the user's name so not email address but name this time and we're going to hope that they type in their name properly like David ma but some users might be in the habit for whatever reason of typing their name backwards if you will with the comma such as men comma David instead now it's fine because both are clearly as readable to the human but if you want to standardize how those names are stored in your system perhaps a database or CSV file or something else it would be nice to at least standardize or canonicalize the format in which you're storing your data so that if you print out the user's name it's always the same format David Ma and there's no commas or backwards to it so let's go ahead and do something familiar let's go and give myself a variable called name and set it equal to the return value of input asking the user as we've done many times what's your name question mark I'm going to go ahead and proactively at least clean up some messiness as we keep doing here by just stripping off any leading or trailing whites space just in case the user accidentally hits the space bar we don't want that ultimately in our data set and now let me go ahead and do this as we've done before let me just go ahead quickly and print out just to make sure I'm off to the right start hello and then in curly brace's name so making an F string to format hello comma name now let me go ahead and clear my screen and run python of format. let me behave and type in my name as I normally would David space ma enter and I think the output looks pretty good it looks as expected grammatically let me now go ahead though and play this game again but this time maybe because I'm not thinking or I'm just in the habit of doing last name comma first I do ma comma David and hit enter all right well this now is is weird even though the program is just spitting out exactly what I typed in arguably this is not close to correct at least grammatically it should really say hello David ma now maybe I could have some if conditions and I could just reject the user's input if they type a comma or get their names backwards somehow but that's going to be uh too little too late if the user has already submitted a form online and I already have the data and now I need to go in and clean it up and it's not going to be fun to go through manually in Google spreadsheets or apple numbers or Microsoft Excel and manually fix a lot of people's names to get rid of the commas and move the first name before the last as is conventional in the US so let's do this it could be a little fragile but let's like let's start to express ourselves a little programmatically here and ask this if there is a comma in the person's name which is pythonic I'm just asking the question is this shorter string in this longer string then let me go ahead and do this let me go ahead and grab that name in the variable split on not just the Comm but the space after assuming the human typed in a space after their name and let me go ahead and store the result of that splitting of ma comma David into two variables let's do last comma first again unpacking the sequence of values that comes back now let me go ahead and reformat the name so I'm going to forcibly change the user's name to be as I expect so name is actually going to be this format string first name then last name both in curly braces but formatted together with a single space so that I'm overriding the user's input and updating my name variable accordingly for the moment to be clear this program is interactive like the users like me are typing their name into the program but imagine the data already is in a CSV file it came in from some process like a Google form or something else online you could imagine writing code similar to this but that maybe goes and reads that file into memory first maybe it's a CSV via CSV reader or a dict reader and then iterating over each of those names but we'll keep it simple and just do one name at a time but now what's kind of interesting here is if I go back to my terminal window and clear it and run python of format. piy and hit enter I'm going to type in David space ma as before and I think we're still good but I'm also going to go ahead and do this python of format. ma comma David with a space in between crossing my fingers and hit enter and voila that now has been fixed such a simple thing to be sure but it is so commonly necessary to clean up users input here we see at least one way to do so pretty easily now to be fair there's some problems here and in fact can someone imagine a scenario in which this code really doesn't fix the user's input what could still go wrong even with this fix in my code any thoughts if they type their in their name comma and then sign them oh and then something else yeah so let me let me try this for instance let me go ahead and run a program and uh I am the only David men that I know but suppose I were uh uh let's say junior like this and it's common in English at least to sometimes put a comma there you don't necessarily need the comma but I'm one of those people who uses a comma that's now really really broken so I've broken some assumption there and so that could certainly go wrong here what else well let me go ahead and run this again and if I did ma comma David no space because I'm being a little sloppy I'm not paying attention which is going to happen when you have lots of users ultimately well this really broke now notice I have a value error an actual exception why well because split is supposed to be splitting the string into two strings by looking for the comma and a space but if there is no comma in space it can't split it into two things and the fact that I have two variables on the left but I'm only getting back one thing on the right means that I can't do this code quite as this so it's fragile to be sure but wouldn't it be nice if we could at least improve it for instance we now know some regular expression syntax what if I at least wanted to make this space optional well I could use my new found regular expression syntax and put a question mark question mark means zero or one of the things to the left what's the thing to the left it's literally a space I don't even need parentheses if there's just one thing there so that would be the start of a pattern that says I must have a comma and then I may or may not have a space zero or one spaces there after unfortunately the version of split that's built into the stir variable as in this case doesn't support regular Expressions if we want our regular Expressions we need to go use that Library here so let me go ahead and do this let me go in and leave this code AS is but go up to the top now and import re to import the library for regular expressions and now let me go ahead and start changing my Approach here I'm going to go ahead and do this I'm going to use the same function called re. search and I'm going to search for a pattern that I think will be last comma first so let me use my new found regular expression syntax and represent a pattern for something like ma comma space David how can I do this well inside of my quotes for re. search I'm going to have something so plus sorry I'm going to have something so plus then I'm going to have a comma then I'm going to have a space then I'm going to have something plus now I'm going to preemptively refine this a little bit I want this whole pattern to start matching at the beginning of the user's input so I'm going to add the carrot right away and I want the end of the user's input to be matched as well so that I'm literally expecting any character one or more times then a comma then a space then any other character one or more times and then that is it and I'm going to pass in the name variable as before now when we've used re do search in the past we really used it just to answer a question does the user's input match the following pattern or not true or false effectively but re. search is actually more powerful than that you can actually get back more information and you can do this you can specify a variable and then an assignment operator and get back more precise answers to what has been found when searched for but what is it you want to get back well it turns out there's this other feature of regular Expressions which allow you to use parentheses not just to group things together but to capture them it turns out when you specify parentheses in a regular expression unbeknownst to us up until now everything in the parentheses will be returned to you as a return value from the re. search function it's going to allow you to extract specific amounts of information from the user's own input you can reverse this process too by using the non-capturing version as well you can use parentheses and then literally a question mark and a colon and then some other stuff and that will say don't bother capturing this I just want to group things but for now we're going to use just the parentheses themselves so how am I going to do this well if I want to get back the user's last name and first name I think what I want to capture is the plus here and the plus here so I've deliberately surrounded in par parentheses the dot plus both to the left and the right of the comma not because I'm grouping them together per se I'm not adding a question mark I'm not adding of another Plus or a star I'm using parentheses now for capturing purposes why well I'm going to do this next I'm going to still ask a Boolean question like if there are matches then do this so if matches is not effectively false like none I do expect I've gotten back some matches and watch what I can do now I can do last comma first equals whatever matches in and get back all of the groups of matches then go ahead and update name just like before with a format string and do first and then last in curly braces as well and then at the very bottom just like before print out for instance hello comma name so the new code now is everything highlighted here I'm using re search to search for whether the US user typed their name in last comma first format but I am more powerfully using re. search to capture some of the user's input what's going to get captured anything I surround it in parentheses will be returned to me as return values how do you get at those return values you ask the variable to which you assigned them for all of the groups all of the groups of parentheses that were captured so let me go ahead and do this let me go ahead now and run python of format stop Pi enter and I'm going to type my name as usual in this case nothing happens with this if condition why because I did not type a comma and so this search does not find a comma so there are no matches so we immediately just print out hello name nothing interesting or new there but if I now go ahead and clear my screen and run python a format up high and do maen commas space David enter we've reformatted my name well how did this work let me be a little more explicit now it turns out I don't have to just say matches. groups I can get specific groups back that I want so let me change my code a little bit more let me go ahead now and just say this let's update name uh to well actually let's do this let's say that the last name is going to be in the matches but specifically group one the first name is going to be in the matches but specifically group two why one and two because this is the first set of parentheses to the left of the comma this is the second set of parentheses to the right of the comma and based on the input this would be the user's last name in this scenario me this would be the user's first name David in this scenario that's why I'm using group one for the last name and group two for the first name and now I'm going to go ahead and say name equals uh F string again uh first and then last done and let me refine this one last step before we take questions I don't really need these variables if I'm immediately using them let's just go ahead and tighten this up further as we've done in the past for design sake if I want to make the name the concatenation of the person's first name and last name let's just do this matches. group two first plus a space plus matches. group one so it's just up to me to know from left to right this is group one this is group two so group one is last group two is first so if I want to flip them around and update the value of name I can explicitly get group two first concatenate using plus a single space and then concatenate on group one all right that was a lot let me pause to see if there are questions the key difference here is we're still using re. search the exact same way but now I'm using its return value not just to answer a question true or false but to actually get back specific matches anything I captured so to speak with parentheses why is it here we're using one and two instead of Z and one really good question caping the first a good observation in almost every other context we've started counting at zero and one instead of one and two it turns out there's something else in location zero when it comes back from re. search related to the string itself so according to the documentation of this function only one is the first set of parentheses and two is the second set and onward from there just a different convention here other questions uh what if we write nothing like white space comma whes space uh how how we check um true of condition before I answer directly let me just run this and make sure I've not broken anything further let me run python of format. let me type in David space maen the right way let me run it once more let me type it Ma comma David the wrong way that we're fixing and we're still good but I think it will still break let me run it a third time with me comma David with no space and now it's still broken why because I'm still looking for comma space now how can I fix that one way I could do that is to add a question mark here which again is zero or more of the thing before so if I have a space and then a question mark literally no need for any parentheses then I can literally tolerate both ma comma space David or ma comma David so let's try again before this did not work let's do me comma David with no space now it does actually work so we can tolerate different amounts of white space if I am a little more precise with my formula let me go ahead and try once more let me very weirdly but possibly hit the space bar a few too many times so now they're really separated this again is uh not going to work quite right because it's going to consume all of that white space so now I might want to strip left and right any of the leading white space on the result or what I could do here is say this instead of zero or one I could use a star here so space star and now if I run this once more with ma comma space space space David enter now we've cleaned up things further so you can imagine depending on how messy the data is that you're cleaning up your regular Expressions might need to get more and more sophisticated it really depends on just how many problems we want to solve at once well allow me to propose that we Forge ahead further just to clean this up even more so using a feature that's actually relatively new to python itself it is very common when using regular Expressions to do exactly what I've done here to call a function like re. search with capturing parentheses inside such that you get back a return value that I'm calling matches you could call it something else but I'm calling it by default matches and then notice on the next line I'm saying if matches wouldn't it be nice if I could just tighten things up further and do these all on the same line well you can sort of let me go ahead and do this let me get rid of this if and let me just try to say something like this if matches equals re search and then colon so combining my if condition into just one line instead of those two um in C or C++ or Java you would actually do something like this surrounding the whole thing with parentheses sometimes double sets to suppress any warnings if you want to do two things at once if you want to not only assign the return value of re. search to a variable called matches but you want to subsequently ask a Boolean question is this effectively true or false that's what I was doing a moment ago let me undo this a moment ago I was getting back the return value and assigning it to matches and then I was asking the question well it turns out this need to have two lines of code presumably rubbed people wrong for too long long in Python and so you can now combine these two kinds of lines into one but you need a new operator you cannot just say if matches equals re search and then an cin at the end you instead need to do this you need to do colon equals if and only if you want to assign something from right to left and you want to ask an if or an L if question on the same line This is affectionately known as you can see here as the wall operator and it's new to python in recent years and it both allows you to assign a value as I'm doing from right to left and ask a Boolean question about it like I'm doing with the if or equivalently L if does anyone know why this is called The Walrus operator if you kind of look at it like this perhaps if you're familiar with walruses it kind of sort of looks like a walrus so a minor detail but a relatively new feature of python that honestly you'll probably continue to see online and in source code and in textbooks and so forth increasingly so now that it does exist it does not change the logic at all if I run python of format. piy and type maen commas space David it still fixes things but it's tightened up my code just a bit more all right let's go ahead and look at one final problem to solve that of extracting information now as well so at this point we've now validated the user's input by checking whether or not it meets a certain pattern we've cleaned up the users input by checking against a pattern whether it matches or not and if it does match we kind of reorganize some of the users information so we can clean up their input and standardize the format in which we're storing or printing it in this case let's do one final example where we're very specifically extracting information in order to answer some question so let me propose this let me go ahead and close format. and create a new file called twitter. the goal of which is to prompt users for the URL of their Twitter profile and extract from it infer from that URL what is the user's username now why might you want to do this well one you might want users to be able to just very easily copy and paste the URL from their own Twitter profile into your form into your app so that you can figure out what their uh username is or you might have a form that asks the user for their Twitter username and because people aren't necessarily paying very close attention some people type their username some people type their whole URL or something else altogether it would be nice now that you're a programmer to just be more tolerant of different types of input and just take on the burden of canonicalizing standardizing the data but being flexible with the users it's arguably a better user experience if you just let me copy paste or type in what I want you clean it up you're the programmer not me LS for a better experience perhaps well let me go ahead and do this with twitter. let me first go ahead and prompt the user here for a value for a variable that I'll call you URL and just ask them to input the URL of their Twitter profile I'm going to go ahead and strip off any leading or trailing whitespace just in case users accidentally hit the space bar that's like literally the least I can do quite easily but now let's go ahead and do this suppose that the users address is the following let me print out what they type in and let me clear my screen and run python of twitter. I'm going to go ahead and type in for instance https twitter.com David J ma which happens to be my own Twitter username for now we're just going to print it back onto the screen just to make sure I've not messed up yet okay so I've printed back out the exact same URL but the goal at hand is to extract the username only now let me just ask perhaps a straightforward question logically what do I need to do to get at the user's username well um we just ignore what's before the username and then just extract the username perfect yeah I mean it is simple as that if you know the usernames at the end well let's just somehow ignore everything to the beginning well what's at the beginning well it's a URL so we're probably going to need to ignore an https a colon a twitter.com and a slash so we just want to throw all of that away why because if it's a URL We Know by how Twitter works that the username comes at the end so let's use that very simple idea to get at the information we want well I'm going to try this a few different ways let me go back into my program here and instead of just printing it out which was just to see what's going on let me do this let me create a new variable called username and let me call url. replace it turns out that if URL is a string or a stir in Python it again comes with multiple methods like strip uh and split and others as well one of which is called replace and replace will do just that you pass a two arguments the first of which is what do you want to replace the second argument is what do you want to replace it with so if I want to get rid of as I've been proposed really just everything before the username that is the Twitter URL or the beginning thereof let's just say this go ahead and replace https twitter.com close quote that's what I want to replace and comma second argument what do you want to replace it with nothing so I'm literally going to pass in quote unquote to effectively do a find and replace that's what the replace method does just like you can do it in Microsoft Word or Google Docs this is the programmer's way of doing find and replace now let me go ahead and print out just the username so I'll use an F string like this I'll say username colon and then in curly braces username just to format it nicely all right let me go ahead and clear my screen and run python of twitter. enter URL here we go https [Music] twitter.com davidj maen enter okay now we've made some progress done for the day right well what is suboptimal about this can anyone critique or find fault with my program it is working now but it's a little fragile I bet we could contrive some scenarios where I think it works but it doesn't well I have a few ideas actually well first of all uh if we if we don't specify https it will broken secondly if we have slash at the end it also will be broken if we if we have like question mark up the after question mark it also w't work so lot of scenar actually oh my God I mean here we are I was pretending to think I was done but my God like Alex gave us a whole laundry list of like problems and just to recap then what if it's not https it's HTTP slightly less secure but I should still be able to tolerate that programmatically uh what if the protocol is not there what if the user just typed twitter.com davidj maen it would be nice to tolerate that rather than show an error and make me type in the protocol why it's not good user experience what if it had a flash at the end of the username or a question mark If you think about URLs you've seen on the web there's very commonly more information especially if it's been shared on social media there might be HTTP parameters so to speak just stuff there that we don't want there could be a www. twitter.com which I'm also not expecting but does work if you go to that URL too so there's just so many things that can go wrong and even if I come back to my contrived example as earlier what if I run this program and say this uh my username is H H gtps twitter.com davidj maen enter well that too just just didn't really work it got rid of the U actually okay actually that kind of worked but the goal here is to actually get the user's username not an English sentence describing the user's username so I would argue that even though I just accidentally created perfectly correct English grammar I did not extract the Twitter username correctly I don't want words like my username is as part of my input so how can we go about improving this and maybe chipping away at some of those problems one by one well let me clear my screen here let me come back up to my code and let me not just replace it but let me do something else instead I'm going to go ahead and instead of using replace I'm going to use another function called remove prefix a prefix is a string or a substring that comes at the start of another so if I remove prefix I don't need a second argument for this function I just need one what prefix do you want to remove so this will at least now fix the problem I just described of typing in like a whole sentence where the URL is there but it's not the beginning it's only at the end so here this still is not correct but we don't create this weird looking output that just removes the URL part of the input uh my username is htps twitter.com davidj maen a moment ago it did remove the URL and left only the David J ma this is not perfect still but at least now it does not weirdly remove the URL and then leave the English it's just leaving it alone so maybe I could handle this better but at least it's removing it from the part of the string I might anticipate well what else could we do here well it turns out that like regular Expressions just let us express patterns much more precisely we could spend all day using a whole bunch of different python functions like remove prefix or remove and strip and others and kind of make our way to the right solution but a regular expression just allows you to more succinctly if admittedly more cryptically Express these kinds of patterns and goals and we've seen from parentheses which can be used not just to group symbols together as sets but to capture information as well we have a very powerful tool now in our toolkit so let me do this let me go ahead and start fresh here and import the re Library as before at the very top of my program I'm still going to get the user's URL via the same l of code but I'm now going to use another function as well it turns out that there's not just re. search or rd. match or re. full match there's also re. sub in the regular expression Library where sub here means substitute and it takes more arguments but they're fairly straightforward the first argument to re.sub is the pattern the regular expression that you want to look for then you have a replacement string what do you want to replace that pattern with and where do you want to do all that well you pass in the string that you want to do the substitution on then there's some other arguments that I'll wave my hands at for now among them are the same flags and also a count like how many times do you want to do find and replace do you want it to do all or do you want to do it just one or so forth you can have further control there too just like you would in Google Docs or Microsoft Word well let me go back to my code here and let me do this I'm going to go ahead and call re not search but re.sub for substitute I'm going to pass in the following regular expression https twitter.com uh Slash and then I'm going to close my quote and now what do I want to replace that with well like before with the simple stir replace function I want to replace it with nothing just get rid of it alt together but what uh string do I want to pass in to do this to the URL from the user and now let me go ahead and assign the return value of re sub to a variable called username so re sub purpose in life is again to substitute some value for some regular expression some number of times it essentially is find and replace using regular expressions and it returns to you the resulting string once you've done all those substitutions so now the very last line of my code can be the same as before print and I'll use an F string username colon and then in curly braces username so I can print out literally just that all right let's try this and see what happens I'll clear my terminal window run python of twitter. and here we go https twitter.com davidj cross my fingers and hit enter okay now we're in business but it is still a little fragile and so let me ask the group what problem should I now further chip away at they've been said before but let's be clear what's one or more problems that still remain the protocols and the uh domain prefixes for good the protocol so HTTP versus https maybe the subdomain www should it be there or not and there's a few other mistakes here too let me actually stay with the group what are some other shortcomings of this current solution um if we use a phrase like you do before we are going to have the same problem because it's not taken account in the first part of the the text example good I might still allow for like some words uh some English to the left of the URL because I didn't use like my carrot symbol so I'll fix that and any final observations on shortcomings here uh well it could be a HTTP or they could be like less than two slashes okay so it could be HTP and I think that was mentioned too in terms of protocol there could be fewer than two slashes that I'm not going to worry about if the user gives me one slash instead of two that's really user error and I could be tolerant of it but you know what at that point I'm okay yelling at them with an error message saying please fix your input otherwise we could be here all day long trying to handle all possible typos for now I think in the interest of usability or user experience ux let's at least be tolerant of all possible valid inputs or reasonable inputs if you will so let me go here and let me start chipping away at these here what are some problems we can solve well let me propose that we first address the issue of matching from the beginning of the string so let me add the carrot to the beginning and let me add not a dollar sign at the end though right because I don't want to match all the way to the end because I want to tolerate a username there so I think we just want the carrot symbol there there's a subtle bug that no one yet mentioned and let me just kind of highlight it and see if it jumps out at you now it's a little subtle here on my screen I've highlighted in blue a final bug here maybe some Smiles on the screen yeah can we take one hand here why am I highlighting the dot in twitter.com even though it definitely should be there so the dot without a backlash mean any character is up a new line yeah exactly it's not it's means any character so I could type in something like Twitter uh question markc or Twitter anything com and that would actually be tolerate it's not really that bad cuz why would the user do that but if I want to be correct and I want to be able to test my own code properly I should really get this detail right so that's an easy fix too but it's a common mistake anytime you're writing regular Expressions that happen to involve special symbols like dots in a URL or domain name a dollar sign in something involving currency remember you might indeed Need to Escape it with a backslash like this here all right let me ask the group about the protocol specifically https is a good thing in the world it means secure there is encryption being used so generally you like to see https but you still see people typing or copy pasting HTTP What would be the simplest fix here to tolerate as has been proposed both HTTP and https I'm going to propose that I could do this I could do HTTP vertical bar or https which again Means A or B but I think I can be smarter than that I can keep my code a little more succinct any recommendations here for tolerating HTTP or https we could try to put an question mark behind the perfect just use a question mark right like both of those would be viable Solutions if you want to be super explicit in your code fine use parentheses and say HTTP or https so that you the reader your boss your teacher just know exactly what you're doing but you know if you keep taking the more of a Bose approach all the time it might actually become less readable certainly once your regular Expressions get this big instead of this big so let's save space where we can and I would argue that this is pretty reasonable so long as you're in the habit of reading regular expressions and know that question mark does not mean a literal question mark but it means zero or one of the thing before I think we've effectively made the S optional here now what else can I do well suppose we want to tolerate the www dot which may or may not be there uh but it will work if you go to a browser I could do this www. uh wait I want a backs slash there so I don't repeat the same mistake as before but this is no good either because I want to tolerate www being there or not being there and now I've just required that it be there but I think I can take the same approach any recommendations how do I make the www dot optional just to hammer this home we can like group uh make a and question mark perfect so question mark is the short answer again but we have to be a little smarter this time as Maria's noted we need parentheses now because if I just put a question mark after the dot that just means the dot is optional and that's wrong because we don't want the user to type in wwwt w i TT e r we want the dot to be there or just not at all with no www so we need to group this whole thing together put a parenthesis there and then a parenthesis not after the third W after the dot so that that whole thing is either there or it's not there and what else could we still do here you know there's going to be one other thing we should tolerate and it's been said before and I'll pluck this one off what about the protocol like what if the user just doesn't type or doesn't copy paste the HTTP colon slash or an https colon right honestly you and I are not in the habit generally of even typing the protocol anymore nowadays you just let the browser figure it out for you and automatically add it instead so this one's going to look like more of a mouthful but if I want this whole thing here in blue to be optional it's actually the same solution as Maria offered a moment ago I'm going to go ahead and put a parenthesis over here and a parenthesis after the two slashes and then a question mark so it's to make that whole thing optional as well and this is okay it's totally fine to make this whole thing optional or inside of it this little thing just the S optional as well so long as I'm applying the same principles again and again either on a small scale or a bigger scale it's totally fine to Nest one of these inside of the other questions now on any of these refinements to this parsing this analyzing of Twitter what if we put a vertical bar besides this www do what if we use a a vertical bar there so we could do something like that too we could do something like this uh instead of the question mark I could do www. or nothing and just leave that in the parenthesis that too would be fine I personally tend not to like that because it's a little less obvious to me wait a minute is that deliberate or did I forget to finish my thought by putting something after the vertical bar but that too would be allowed there as well if that's what you mean other questions on where we left things here where we made the protocol optional too what coulden if we have parenthesis and then inside we have another parenthesis and another parenthesis to feel with each other if you have parentheses inside of parentheses that too is totally fine and indeed that should be one of the reassuring lessons today as complicated as each of these regular Expressions has admittedly gotten I'm just applying the exact same principles in the exact same syntax again and again so it's totally fine to have parentheses inside of parentheses if they're each solving different problems and in fact the lesson I would really emphasize the most today is that you will not be happy if you try to write out a whole complicated regular expression all at once like if you're anything like me you will fail and you will have trouble finding the mistake because my God look at these things they are even to me all these years later cryptic the better way I would argue whether you're new to programming or as old to it as I am is to just take these baby steps these incremental steps where you do something simple you make sure it works you add one more feature make sure it works add one more feature make sure it works and hopefully by the end because you've done each of those steps one at a time the whole thing will make sense to you but you'll also have got gotten each of those steps correct um at each turn so please do avoid the inclination to try to come up with long sophisticated regular Expressions all at once because it's just not a good use of a time if you then stare at it trying to find a mistake that you could have caught if you did things more incrementally instead all right there Still Remains arguably at least one problem with this solution in that even though I'm calling re.sub to substitute the URL with nothing quote unquote I then on my final line of code line six I'm just blindly assuming that it all worked and I'm going to go ahead and print out the username but what if the user if I clear my screen here and run python of twitter. doesn't even type a Twitter URL what if they do something like https www.google.com slash like completely unrelatedly for whatever reason enter that is not their Twitter username so we need to have some conditional logic I would argue so that for this program's sake we're only printing out or in a backend system we're only saving into our database or a CSV file the username if we actually matched the proper pattern so rather than use re.sub which is useful for cleaning up data as we've done here to get rid of something we don't want there why don't we go back to re. search where we began today and use it to solve the same problem but in a way that's conditional whereby I can confidently say yes or no at the end of my program here's the username or here it is not so let me go ahead now and I'll clear my terminal window here I'm going to keep most of uh the I'm going to keep the first two lines the same where I import re and I get the URL from the user but this time let's do this let's this time search for using re. search instead of re.sub the following I'm going to start matching at the beginning of the UR of the string https uh question mark to make the S optional colon SL slash then I'm G to make my uh www uh optional by putting that in question marks there then a twitter.com with a literal dot there so I'll stay ahead of that issue too then a slash and then well this is where David J ma is supposed to go how do I detect this well I think I'll just tolerate anything at the end of the URL here all right dollar sign at the very end close quote for the moment I'm going to stipulate that we're not going to worry about question marks at the end or hashes like for fragment IDs and URLs we're going to assume for Simplicity now that the URL just ends with the username alone now what am I going to do well I want to search for this URL specifically and I'm going to ignore case so rei. ignore case uh uh applying that same lesson learned from before rei. search recall will return to you the matches you've captured well what do I want to capture well I want to capture everything to the right of the twitter.com URL here so let me surround what should be the user's username with parentheses not for making them optional but to say capture this set of characters Now ar. search recall returns an answer matches will be my variable name again but I could call it anything I want and then I can do this if matches now I know I can do this let's print out the format string username colon and then uh what do I want to print out well I think I want to print out matches. group one for my matched username all right so what am I doing just to recap line one I'm importing the library line two I'm getting the URL from the user so nothing new there line five I'm searching the user's URL as indicated here as the second argument for this regular expression this pattern I have surrounded the plus with parentheses so that they are captured ultimately so I can't extract in this final scenario the user's username if I indeed got a match and matches is non none it is actually containing some match then and only then print out username in this way let me try this now if I run python of twitter. and type in HTTPS www.google.com now nothing gets printed so I've at least solved the mistake we just saw where I was just assuming that my code worked now I'm making sure that I have searched for and found the Twitter URL prefix all right well let's run this for real now python of twitter. https twitter.com davidj maen but note I could use HTTP I could use www I'm just going to go ahead here and hit enter huh none what has gone wrong this one's a bit more subtle but why does matches. group one contain nothing wait a minute let me maybe I maybe I did this wrong Maybe maybe do we need the www let me run it again so here we go https let add it www. twitter.com davidj mail all right enter what is going on we have to say group group I have to say group two well wait all right because we had the the subdomain was optional and to make it optional I needed to use parentheses here and so I then said zero or one okay so that means that actually I'm unintentionally but by Design capturing the www dot or none of it if it wasn't there before but I have a second match over here because I have a second set of parentheses so I think yep let me change matches group one to matches group two and let's rerun this python of twitter. https www. Twitter let's do this uh twitter.com David J ma enter and now we've got access to the username let me go ahead and tighten it up a little bit further uh if you like uh our new friend uh it's hard not to like if we like our old friend the wallus uh operator let's go ahead and add this just to tighten things up let me go back to vs code here and let me get rid of the unnecessary condition there and combine it up here if matches equals that but let's change the single assignment operator to the Wallace operator now I've tightened things up further but I bet I bet I bet there might be another solution here and indeed it turns out that we can come back to this final set of syntax recall that when we introduced these parentheses we did it so that we could do a or b for instance with the vertical bar though you can even combine more than just one bar we use the group to combine ideas like the www do and then there's this admittedly weird syntax at the bottom here up until now not used there is a non capturing version of parentheses if you want to use parentheses logically because you need to but you don't want to bother capturing the result and this would arguably be a better solution here because yes if I go back to vs code I do need to surround the www.t with parenthesis at least as I've written my Rex here because I wanted to put the question mark after it but I don't need the www dot coming back in fact let's only extract the data we care about just so there's no confusion down the road for me or my colleagues or my teachers so what could I do well the syntax per this slide is to use a question mark and a colon immediately after the open parenthesis it looks weird admittedly those of you who have prior programming experience might recognize the syntax from Turner operators doing an if else allinone line a question mark colon at the beginning of that parenthetical means yes I'm using parentheses to group these things together but no you do not need to capture them instead so I can change my code back now to matches. group one I'll clear my screen here run python of twitter. I'll again run here uh https twitter.com davidj maen with or without the www and now I indeed get back that username any questions then on these final techniques so first of all could we move the carrot right at the beginning of Twitter and then just start reading from there and then get rid of everything else before that the kind of WWE uh issues that we had and then my second question is how would we um use kind of I guess it either a list or a a dictionary to to sort the do kind of thing because we have dood UK and that kind of St how would we bring that into uh the re function a good question but no if I move the carrot before twitter.com and throw away the protocol and the www then then the user is going to have to type in literally twitter.com username they can't even type in that other stuff so that would be a regression a step back as for the do and the.org and.edu and so forth the short answer is there's many different solutions here if I wanted to be stringent about do and suppose that Twitter probably owns multiple domain names even though they tend to use just this one suppose they have uh something like.org as well you could use more parentheses here and do something like this Comm or org I'd probably want to go in and add a question mark colon to make it non-capturing because I don't care which it is I just want to tolerate both alternatively we could capture that we could do something like this where we do dot plus so as to actually capture that and then we could do something like this if matches. group one now equals equals Comm then we could support this so you could imagine factoring out the logic just by extracting the top level domain or TLD and then just using python code maybe a list maybe a dictionary to validate elsewhere outside of the redx if it's in fact what you expect for now though we kept things simple we focused only on the Doom in this case let's make one final change to this program so that we're being a little more specific with the definition of a Twitter username it turns out that we're being a little too generous over here whereby we're accepting one or more of any character I check the documentation for Twitter and Twitter only only supports letters of the alphabet A through Z numbers 0-9 or underscore so not just dot which is literally anything so let me go ahead and be more precise here at the end of my string let me go ahead and say this set of symbols in square brackets I'm going to go ahead and say a through z uh 0 through 9 and an underscore because again those are the only valid symbols I don't need to bother with an uppercase a or a lowercase C because we're using re. ignore case over here but I want to make sure now that I tolerate not only one or more of these symbols here but also maybe some other stuff at the end of the URL I'm now going to be okay with there being a slash or a question mark or a hash at the end of the URL all of which are valid symbols in a URL but I know from the Twitter's documentation are not part of the username all right now I'm going to go ahead and run python of twitter. one final time typing in HTTPS twitter.com David M maybe with maybe without a trailing slash but hopefully with my biggest fingers crossed here I'm going to go ahead now and hit enter and thankfully my username is indeed David J Ma so what more is there in the world of regular expressions and this own Library not just re. search and also re.sub there's other functions too there's re dosit via which you can split a string not using a specific character or characters like a comma and a space but multiple characters as well and there's even functions like re . findall which can allow you to search for multiple copies of the same pattern in different places in a string so that you can perhaps and manipulate more than just one so at the end of the day now you've really learned a whole other language like that of regular expressions and we've used them in Python but these regular Expressions actually exist in so many languages too among them JavaScript and Java and Ruby and more so with this new language even though it's admittedly cryptic when you use it for the first time you have this new found ability to express these patterns that again you can use to validate data to clean up data or even extract data and from any data set you might have in mind that's it for this week we will see you next time [Music] [Music] all right this is cs50's Introduction to programming with python my name is David men and this is our week on objectoriented programming or oop it turns out that in the world of programming there's different paradigms of programming languages there's different ways of solving problems with code and it's a little hard to see this at first if you've only learned one language but over time if and when you learn other languages besides python you'll start to notice certain patterns and certain capabilities of some languages but not another thus far within the world of python you and I have largely been writing code that's procedural in nature whereby we're writing procedures we're writing functions and we're sort of doing things top to bottom everything is step by step by step as you would expect in general from an algorithm but along the way we've actually dabbled in another Paradigm known as functional programming with python whereby we've been able to pass functions around we even had an anonymous function some weeks ago and that's evidence of features of a functional programming language even though we've just scratched the surface thereof today we focus on another Paradigm and this one in more detail namely objectoriented programming and now while some of you might have prior programming experience and have learned languages like Java which are by Design fundamentally objectoriented python indeed allows you a bit of flexibility when it comes to how you solve problems with code but it turns out oop object ented programming is a pretty compelling solution to problems that you invariably encounter as your programs get longer larger and more complicated so indeed oop for our purposes is going to be a solution to a problem that builds on so many of the lessons past so let's go ahead and do this let's start by writing a program very procedurally by opening up VSS code here I'm going to go ahead and create a program called student. and in this program I want to do something relatively simple initially uh as we might have done some weeks ago now where I just ask a user for their name and maybe in the context of the Harry Potter Universe their house and just print out where that student is from and let's gradually enhance this program by adding more and more features to it and see if we don't stumble upon problems that up until now we might not have had very elegant well-designed solutions to but if we introduce explicitly object-oriented programming as a programming technique I bet we can clean up our code and set the stage for writing even more sophisticated programs longer programs down the line so in student. piy let me go ahead and do a name variable setting it equal to the return value of input and just prompt the user for their name like this and then let me go ahead and do the same for a house variable and prompt the user for their house using input like this and let's do something super simple now let's just go ahead and print out an F string that says something like name from house just so that I can confirm that the contents of these variables are indeed as I expect I'm not do any error checking or trimming or anything like that for now I'm really just going to spit back out whatever the user just typed in all right let me go ahead and run python of studenty let's use our go-to like Harry as in Harry Potter from Gryffindor and when I hit enter now let's see if I see that Harry from Gryffindor is indeed the case all right so I think we have a working program at this point but let's now introduce some of those Lessons Learned way back from week zero where we started writing our own functions not necessarily because it solves the problem more correctly I dare say this is correct as is but it begins to give us building blocks that we can extend so as to solve more complicated programs so let me go back up to student. and let's go ahead now and do this let's put the entire logic I just wrote inside of our typical method called Main and let me indent those three lines so that at least they're now combined into one main method but instead of using input on line two and input on line three why don't we go ahead and assume for the moment that we've got some function called get name in the world and let's go ahead and assume we've got another function like get house in the world that don't take parameters but their purpose in life is by their Nam going to be to get the user's name and to get their user house respectively and then I'm going to print out the exact same F string as before I of course need to implement these functions now so let me go lower in my file and Define a function called get uncore name nothing in these parentheses because it's not going to take a parameter and I'm going to go ahead and do something like name equals input quote unquote name just like before and then I'm going to go ahead and return name so it's a super simple function but it's a an abstraction I now have a function called get name whose implementation details I don't have to care about anymore I just know that the function exists and I can tighten this up in fact I don't really need a name variable on line 8 if I'm immediately going to return that same name variable on line nine so let me just tighten this up a little bit even though it doesn't change the functionality and just immediately return the return value of the inputs uh function call here let's do something very similar now for get house which will similarly take no arguments I'm going to go ahead and return the return value of input this time prompting the user for their house and I need one final detail at the very bottom let's continue our habit of doing if the name of this file equals equals quote unquote main then let's go ahead and actually call Main and recall that we have that in place so that if this eventually becomes part of a module a library of sorts I don't accidentally call Main blindly I only do it if I mean to run main from the command line on this file all right so if I didn't make any mistakes here let me go ahead and in my terminal window again run python of student. enter let's type in Harry enter let's type in Gryffindor enter and we're set Harry from Gryffindor seems to still be working so we haven't really solved the problem anymore correctly but I've laid the foundation to maybe now do some more interesting things because I've have these building blocks in place all right but let me propose that we could be doing this a little bit differently get name get house is fine but at the end of the day I'm really trying to get a student from the user I want their name and their house not just one or the other so maybe it would be a little cleaner still to define a function called get student and let get student do all of this work for us now theoretically get student could call get name and could call get house but because these functions are so short I think I'm okay with just defining one function called get student that similarly won't take any arguments but it's going to do two things it's going to get the student's name by prompting them with input as before and it's going to get the student house by also prompting them as before and then now hm I want to return the student but I think I might have painted myself into a corner here because I now have two variables name and house and yet up until now we've pretty much returned one or the other we've returned one value so any suggestions for how we can perhaps solve this problem that I just created for myself whereby I want to return really a student but I currently have a name variable and a house variable I'd minimally like to return both of those I believe that we can return a dictionary includes the name and the house yeah so we absolutely could return a dictionary a dict object in Python whereby maybe one key is name one key is house and the values thereof are exactly the values of these variables we could totally do that uh I worry that that might be getting a little complicated I wonder if there's a simpler way instead any other instincts even if you're not sure it would work return both name and house return both name and house I I like the sound of that it sounds simple I don't have to figure out what a dictionary is going to look like and in fact this too would be a valid approach even if you've not seen this before it turns out in Python that you can kind of return multiple values but that's a bit of a white lie or we could take Muhammad's approach of actually return rning a dictionary and putting multiple keys there in so here again we have yet another example of how you can solve the same problem in at least two ways and I dare say we're about to see even more so one way you could solve this problem whereby you want to return multiple values would be to do something like this I could go ahead and literally return not just name but I could put a comma and also return house this is not necessarily something you can do in other languages if you have programmed in other languages before it depends on the language but it looks like thanks to this comma maybe I can in fact return two values as actually proposed well if I'm returning two values in this way on line 10 how do I get both values at the same time well there's a couple of ways let me go up to my main function I know minimally I'm going to have to change the get name and get house to get student but what am I going to store the return value in I think I could actually do this and we have seen this technique before where you can unpack so to speak speak sequences of values that are coming back and indeed consider this to be exactly that name comma house is some kind of sequence that I'm returning of values name comma house so if I want to unpack those and store the return values in two separate variables I can in fact use the commas on the left hand side of my assignment operator the equal sign to do just that now to be clear I don't need to call these variables name and house here I could simplify this and use just n here and H here and then I could return just n and H but I would argue that's not very uh clear to the reader as to what's going on so I think in this case even though it's a coincidence that I've used the same variable names in get student and get Main and in Maine it's a little more readable to someone like me so I'm going to leave it as is well let's go ahead and see now if this works let me clear my screen down here and run python of student. enter let's again type in Harry let's again type in Gryffindor enter and voila we still see that Harry is from Gryffindor but what are we actually doing here what are we actually doing by returning this value well it turns out that what we've just done is used a tupple a tupple is another type of data in Python that's a collection of values X comma y or X comma y comma Z it's similar in spirit to a list in that sense but it's immutable it's not mutable now what does that mean a list as we've seen it before is a data structure in Python that you can change the values of you can go into bracket zero for the first location and change the value there you can go to bracket one bracket two bracket three and actually change the values in lists but if you have no intention of changing the values of variables and you want to return effectively multiple values you don't have to even return it as a list you can return it as a tle instead just by using a comma and it turns out we can make explicit that here's the white lie I'm not actually returning two values per se whenever you use a comma in this way on line nine you're actually returning one one value which is a tupple inside of that tupple now are two values so it's similar in spirit to returning one list with two things here I'm returning one tupple with two things and the mere fact that I've used a comma and nothing else tells python that I indeed want to return a tle but there's more explicit syntax that we can use instead I can actually more verbosely put explicit parentheses around the values of this tupple just to make more clear to me to the reader that this isn't two values per se this is one value with two things inside of it and what I can actually do then too is I don't have to unpack this up here so to speak I can actually go up here and maybe give a more apt name like student and I can name the value or rather name the variable in which I'm storing the return value of get student as quote unquote student so maybe this is a little better design now because I'm sort of abstracting away what a student is it's implemented at the moment as a tupple with two values but at least now I have a variable called what I mean a student but there's going to be a catch on line three I still want to print out that Student's name and their house but I don't have a name variable anymore and I don't have a house and I also don't have a dictionary as was proposed earlier so I can't even go at those keys by name but what a tupple is it's very similar in spirit to a list but it is indeed just immutable and what I mean by that is I can still index into it numerically by saying student square bracket Z for the item in the first location in that Tuple and then over here instead of house I can say student bracket one student bracket one is going to give me the second location in that tupple let me go ahead and clear my terminal window again run python of student. let's type in Harry let's type in Gryffindor enter and we still have some working code let me pause here now and see if there are any questions on this technique of returning a tupple and indexing into it in this way I guess what's a like a actual use case where you would use a tupple versus you know a list or something else that's similar it's a really good question when would you use a tuple versus a list when you want to program defensively or in general when you know that the values in this variable shouldn't change so why would you use a data type that allows them to be changed it just invites mistakes bugs down the line either by you or colleagues who are interacting with your code so tupple is just another way where you can increase the probability of correctness by just not letting anyone yourself included change the contents therein so it's just another tool in your toolkit but let's make clear then what I mean by immutable again I claim that immutable means that you cannot change the value well let's go ahead and try to do this let me go ahead and run this program once more as is python of student. let me go ahead and type in for instance uh how about uh padma's name and I'm going to go ahead and say that padma's in Gryffindor as in the movies and we see Padma from Gryffindor but technically I went down this rabbit hole and looking at Harry Potter more closely technically in the books Padma I believe was from Ravenclaw so this is actually a mistake or an inconsistency between the movies and the books let's see if we can't fix this inconsistency in our code so how about we do this if the student's name that's inputed equals Padma why don't we override whatever the uh whatever the house is and change it to be properly Gryffindor let me go ahead and do if student now if I want to get at padma's name I'm going to have to do student bracket zero I have to know what location the name is in in this tupple but if that in value equals equals Padma let's go ahead with this if statement and make a change let's change the students F uh bracket one value so the second value if we're zero indexing let's change it to be another house in the World of Harry Potter called Ravenclaw so I'm just fixing maybe the user's input they watch the movie so they typee in Padma Gryffindor but mm- the books it was Padma from Ravenclaw all right let me go ahead and go down to my terminal window clear my uh terminal and do python of student. enter I'm going to do Harry as well as Gryffindor just to demonstrate that that is still working as intended Let Me Clear My screen again though and run python of studenty on Padma and I'll put her too in Gryffindor as in the movies and hit enter and now I just see a big mess of errors on the screen some kind of exception has been thrown and indeed a type error has happened happened I'm using a data type wherein there's an error and what is that error well tupple object does not support item assignment it's a little arcany expressed that is that's not really very user friendly but if you think about what those words mean tupple object does not support item assignment so assignment is copying from right to left so somehow that's invalid and here is a manifestation of the immutability of tuples you cannot change location zero or one or anything inside that is a feature that is the design of a tuple so if I want to override that I think I'm going to have to use a different type of data that we've used before namely a list and that's fine if you want to enable yourself and colleagues using your code to change the contents of that container well we can go ahead and return not a tupple using explicit parentheses or no parentheses just the comma but I can use square brackets and if I'm using square brackets on the left and the right this is indeed explicitly a list same idea but it's mutable that is to say you can change the contents of a list so making no other changes just returning a list with square brackets instead of a tuple with parentheses or just the comma let me go ahead now and run python of student. enter let me type in Harry and Gryffindor again that's still working good to see let me run this once more and type in Padma and Gryffindor as in the movies but no now we've corrected it to be Padma from Raven claw as in the books instead any questions now on tupples versus lists or this idea of immutability versus mutability uh can we use a nested tle in Pyon like a a nested lists absolutely you can have not only nested lists in Python where one of the elements in a list could be another list so you have some square brackets out here you might have some other square brackets inside you can absolutely do the same with a tupple as well there's no constraint on the types of values you can put in there we've not had occasion to do that in this case I'm just returning a simple uh simple tupple with two elements but yes you could absolutely do that too other questions on tles versus lists okay for example um when I see the square bracket um is it mainly used for the list oh a really good question uh sort of so when you create a value like a list you use square brackets and that would indeed be a visual indicator that this is definitely a list uh if you instead see parentheses that's a visual indicator when creating a value that it's definitely a tupple however somewhat confusingly both lists and topples use square brackets when you access the contents of them when you index into them at location zero or location one you always use square brackets so that's the distinction there good question allow me to propose now if I may that we solve this problem yet another way and let's see if we're either making things Better or For Worse than us recall that dictionaries or dict objects also exist in python and a dictionary is this collection of keys and values and the upside in particular of a dictionary is that they have better semantics right you don't just have to assume that a name is always going to be at location zero house is always going to be at location one I mean that's the kind of thing especially if you had three four or more values eventually you or someone is going to get confused and forget what the order is and you're going to write buggy code so a dictionary is a little more powerful and that you can semantically associate Keys like little descriptions with the values those keys and those values respectively so let me go ahead and do this and we can do this in a few different ways but let me propose that we focus on get student here and let's go ahead and do this let me go ahead and uh in delete the implementation of get student as is let me create a student variable and initialize it to an empty dictionary and I can do that with just two curly braces here and then let me go ahead and set two keys inside of that dictionary inside of the student there will be quote unquote a name key and the value of that is going to be whatever the return value of input is when I prompt the user for their name and then the house key inside of that same student dictionary is going to be the return value of whatever the user types in for their house and lastly I'm going to go ahead and return student so now I am literally returning one thing still but this time it's a dict rather than a tupple rather than a list but there's still two things in it technically four things if you count the keys and the values but there's two key value pairs now my code up here is going to have to change a little bit and let's simplify this and remove for instance now the the Padma if statement just to focus on what's changing at hand and let me go ahead now and leave line two alone I'm still going to have a student variable that gets assigned the return value of get student but what I want to do here now is actually access the keys in inside of that dictionary not by numeric index which was for tuples and lists zero and one but by way of the keys now normally I might be in the habit as I personally am of using double quotes quote unquote name inside of there and quote unquote house inside of there but before I even run this code and show you a mistake see an error on the screen does anyone want to call out what I have done wrong here this is just an F string I just want to print out the value of the name key the value of the house key in this dictionary but your your audio was a little garbled for us but I think I heard double quotes and single quotes so I'm going to assume that indeed you've identified precisely the issue I'm just going to confuse python right now even though this is an F string inside of Double quotes prefixed with an F I can't actually use my double quotes inside my double quotes because that's going to potentially confuse python indeed if I run this program now python of student. py and hit enter I get a syntax error so the program didn't even run fully it just couldn't be understood because it got confused by those double quotes So the simplest fix here would indeed just be to use not double quotes but single quotes around the keys or conversely flip the double quotes on the outside to single quotes then use double quotes on the inside you just want to be consistent so a subtle detail but again this is now specific to dictionary syntax this isn't fundamental to how we're solving this current problem at hand all right well let's go ahead and try this let me go ahead now and run python of student. let's go ahead and type in Harry let's type in Gryffindor and hopefully Harry is back from Gryffindor no syntax errors no other errors I think I'm back in business here and what I do like to be clear about using a dictionary is that it is allowing me just better semantics again I don't have to remember memorize document that zero is name one is house instead name is name and house is house it's just a little clear a little more expressive so that's generally a good thing especially if we stored more data about students than just their name in their house if you had three Fields four five 10 different fields no one's going to want to remember or be able to remember forever which is zero which is one which is two and so forth better to introduce uh names like name and house in this case but let me tighten this up further in indeed I'm typically in the habit of not introducing variables unnecessarily unless they make the code more readable and an alternative way to format the same code would be this strictly speaking I don't need to create an empty dictionary then add one key to it then add a second key to it and then return that dictionary I can actually consolidate this all into one statement if you will let me go ahead and do this let me go ahead and say name equals inputs return value house equals inputs return value and then instead of returning any variable name student which I'm going to propose doesn't need to exist anymore let me just create and return the dictionary all at once let me do quote unquote name in lower case here and then the variable it's storing the user's name then quote unquote house as my second key the value of which is going to be house the variable now is this better maybe maybe not maybe the first wave was a little more readable and that's totally fine to create variables if they improve the readability of your code but just know that you can also create and return a dictionary on the fly like this so to speak all in one line and I think it's arguably pretty reasonable in this why it's just pretty short I probably wouldn't do this if it got longer and longer and longer I might minimally then start moving my key value pairs to separate lines but this would just be a slightly more compact way of doing this as well but let me propose we do one more change let's go ahead and introduce that same special casing of Padma to fix her house from Gryffindor for instance to Ravenclaw how do we do this with dictionaries well dictionaries like lists are mutable you can change what is in them just just like you can lists and how do you do that is just a little different syntactically so let's go back into Main and do this fix if the student variable has a name key that equals equals Padma then indented go ahead and change the value of the house key inside of that student dictionary to be quote unquote Ravenclaw instead so very similar in spirit to what we did with a list but instead of using location zero and one we're much more clearly explicitly semantically using quote unquote name and quote unquote house because you index into lists and topples using numbers but you index into dictionaries using strings as I've done here all right let me go ahead and run python of studenty we'll again do Harry from Gryffindor and I think all as well let me run it one more time this time with Padma who in the movies is from Gryffindor but should really be from Ravenclaw are any questions then on this progression from tuples to lists to dictionaries we haven't necessarily introduced anything new other than those tupples which have been available to us all this time but the goal at the moment is just to demonstrate this distinction among these different data types and how they each work a little bit differently what if a a combination of lists is there in a tle so is the list like we can change the list because tle are imut but lists are mutable correct you can change the contents of lists and you can put most anything you want in them other lists or strings as I've done integers or anything else tuples you can do the exact same thing but you cannot change them once you've created them a dictionary is more like a list in that it is mutable you can change it but the way you index into a dictionary is by way of these Keys these strings as we keep seeing rather than by numbers those numeric indices all right well let me propose that there is yet another way of solving this problem and indeed I would argue that there's now an opportunity to hand even though this program isn't particularly complicated all I'm doing is collecting a name from the user and a uh house from the user you could imagine wanting longer term to collect even more information like the students's Patronis or magical spell or a whole bunch of other information that might belong in a student and right now we're just kind of using these very general purpose data types in Python a tuple to combine some values together a list to do the same but let us change it later a dictionary which is more powerful because it's a little more structured it does have keys and it has values not just values but you know what this we wouldn't have to be having this conversation if the authors of python had just given us a data type called student right wouldn't it have been nice if there were just a type of variable I could create in my code called student then we wouldn't have to figure out well do we use a tuple or a list or a dictionary but that's pretty reasonable right you could imagine just a how slippery of a slope that is so to speak if the creators of a language had to anticipate all the possible types of data that programmers like you and me want to store in your programs so they just gave us these general purpose tools but they gave us another general purpose tool that's going to allow us to create our own data types as well and actually give them names and that uh terminology is a class a class is kind of like a blueprint for pieces of data objects so to speak a class is kind of like a mold that you can define and give a name and when you use that mold or you use that blueprint you get types of data that are designed exactly as you want so in short classes allow you to invent your own data types in Python and give them a name and this is a primary feature uh of objectoriented programming to be able to create your own objects in this way and in the case of python and classes even give them some custom names so what does this mean in real terms well let me go ahead and come back to vs code here and let me propose that we introduce a little bit of new syntax I'm going to go ahead and clear my terminal window first I'm going to go to the top of my file and I'm just going to start a thought but not finish it yet I'm going to use this new keyword for classes called literally class so indeed the new keyword we're going to have here and if I go back to our slides here this this would be the official URL where you can read up more on this particular feature of python in the official tutorial class is a new keyword we can use now this is coincidentally related to students because students take classes but it has nothing to do with the fact that we're dealing with students class is a general purpose term in a lot of languages python among them that allow you to Define these custom containers with custom names for pieces of data so let's go back to VSS code let's use this new keyword and let me propose that we create a class called student and by convention I'm going to use a capital S here and I'm going to go ahead and with a colon get to later the implementation of this class so I'm just going to use dot dot dot which is a valid placeholder for now that just indicates to me that I'm going to come back to implementing this later but as of now it does in fact exist I now have a student uh class defined for me that I can now use in my code here how am I going to use it well first of all let me go down to get student and let me change this code to no longer use a dictionary but to use this class I'm going to do this I'm going to give myself a variable called student as I've done before but I'm going to set it equal to Capital student open parenthesis close parenthesis so I'm going to do what appears to be calling a function and that function student with a capital S notice matches the name that I gave this class at the top of my file all right what do I next want to do I'm going to go ahead and give this student a name now if if I were still using a dictionary I would say student quote unquote name using square brackets but this is not a dictionary it turns out classes have what for now we'll call attributes properties of sorts that allow you to specify values inside of them in the Syntax for that happens to be a DOT we've seen dots before we've used it in the context of modules and libraries more generally this is another similar INSP Spirit use of a DOT that allows you to get at something inside of something else so student. name is going to be the syntax I use for giving this student a name and that name is going to be whatever the return value of name is and then I'm going to go ahead and say student.h house to give another attribute called house and give that the return value of input here prompting the user for house and then as before I'm just going to return student but now what's really powerful about class and objectoriented programming more generally is that I've created this custom data type called literally student capital S I've stored one such student in a variable like I can always do in a variable called student lowercase s but I could call it anything I want I just makes sense to call it student as well but lowercase for clarity and then I'm returning that variable and because of my syntax in lines 14 and 15 that has the result of putting inside of that class a name attribute and a house attribute I just need to make one more change up here I'm going to go ahead and remove our Padma code just so we can focus only on what's new rather than fixing her house and I'm going to go in here and change the syntax that previously was for dictionaries again dictionaries use square brackets and then strings in quotes either single quotes or double quotes depending on the context here though I'm going to change this to be student. name and over here I'm going to change it to be student. house and that's just going to be my new syntax for getting the contents of what appears to be a class called student let me go ahead and rerun python of student. by enter let's type in Harry's name as before let's put him in Gryffindor crossing our fingers as we often do and Harry is indeed from Gryffindor what though have I done let's introduce one other bit of terminology here it turns out that I can create a class using that class keyword but anytime you use a class you're creating what are called objects and here is the word objects as in objectoriented programming or oop let me go back to my code here and even though I haven't really implemented much of it at all I literally just left it with a dot dot dot that's enough code lines one and two to just invent a new data type called student capital s that may or may not have some future functionality as well that's enough to create a class what though am I doing on line 11 on line 11 what I'm technically doing is creating an object of that class so this too is another term of art you create objects from classes so if we go back to that metaphor that a class is like a blueprint for a house or a class is like a mold an object is when you use that blueprint to build a specific house or something that comes out of in plaster the mold when you actually use that mold to create such an object so a class is again the definition of a new data type the object is the Incarnation of or technically instantiation of and another term for objects would actually be an instance you have instances of classes as well so that's a lot of vocabulary but at the end of the day it just boils down to this you can Define your own class which is really your own data type you can then store attributes inside of it using this dot notation here and then you can access those same attributes using Code like this here and now I have a proper student data type and I don't have to kind of hack something together using a tupple or a list or even a dictionary I now have a proper data type called student that the authors of python didn't give me I gave myself any questions now on classes this new keyword class or this idea of these objects or instances thereof is the class object mutable or immutable a good question and we've clearly laid the stage for having that conversation about every data type now we will see that they are mutable but you can make them immutable so you can get the best of both worlds Now by writing some actual code and we'll write more code than the DOT dot dot in just a bit other questions on classes or these objects thereof then what would be the properties of those glasses uh so at the moment the properties of or the attributes of as I've been calling them thus far would just be name and house it turns out that there may very well be other attributes built into classes that we may see before long but for now the only two attributes that I care about are the ones that I myself created namely name and house are again what I would call attributes and in a little bit we're going to start calling those same attributes more technically instance variables name and house as I've presented them here in VSS code are really just variables called name and called house inside of an object whose type is student all right so what more can we do with these classes well again online 11 is where we're instantiating an object of the student class and assigning it to a student variable we're then adding attributes name and house respectively on lines 12 and 13 currently both of those have values that are technically strings or stirs because that's what the return value of input is but those attributes values could actually be any data type we're just keeping things simple and focusing on defining students in terms of two strings name and house and then on line 14 we're returning that variable we're returning that object to main so that we can actually print out who is from what house well let's go ahead and add a bit more functionality here because right now on lines 12 and 13 this is a little manual and it's a little reckless of me to just be putting anything I want inside of this student object it turns out with classes unlike with dictionaries we can actually standardize all the more what those attributes can be and how what kinds of values you can set them to so let me go ahead and do this let me propose that it would actually be really nice if instead of doing this here let me go ahead and simplify my code as follows let me go ahead and give myself a local variable called name and set it equal to the return value of input like we've done many times now already let me give myself one other variable for now called house and set it equal to the return value of input as well prompting the user for their house and now instead of creating a student object from my student class and then manually putting the name attribute inside of it and the house attribute inside of it let me actually do something more powerful let me do this let me call that student function which is identical to the class name just by defining a class you get a function whose name is identical to the class name with the capital letter included but instead of just doing open parenthesis close parenthesis let me pass in the name that I want to fill this this object with and the house that I want to put in that object as well and now let me set the return value as before to be student equals like this so what have I done that's different fundamentally I'm still getting user input in the same same way I'm using input on line 11 and input on line 12 and I just so happen to be storing those return values in local variables but now now we're setting the stage for the more powerful features of classes and object-oriented programming more generally notice that I'm deliberately passing to this capital S student function name comma house I'm passing in arguments to the function now the student class is not going to know what to do with those yet but now I'm sort of standardizing how I'm passing data into this student class and ultimately it's going to give me an opportunity to error check those inputs to make sure that the name is valid that it has a value and it's not just the user hitting enter it's going to allow me to ensure that it's a valid house that it's Gryffindor or Hufflepuff or Ravenclaw or Slytherin or not just hitting enter or some random value that the user types in because I'm passing name and house to the student class this particular function I'm going to have more control over the correctness of my data so let's now go up to the student class which up until now I left as just dot dot dot it turns out that in the context of classes there are a number of not just uh attributes or instance variables that you can put inside but also methods classes come with certain methods or functions inside of them that you can Define and they just behave in a special way by nature of how python works these functions allow you to determine behavior in a standard way they are indeed special methods in that sense now what do I mean by this well let me go back to vs code here and let me propose that I start to define a standard function called uh underscore underscore or Dunder as it's abbreviated in it underscore underscore and then I'm going to go ahead and do open parenthesis and then I'm going to put in here literally the word self more on that in just a moment but now inside of this function I'm going to have an opportunity to customize is this uh classes objects that is to say this underscore uncore init method or Dunder init method is specifically known as an instance method and it's called exactly this this is designed by the authors of python and if you want to initialize the contents of an object from a class you define this method and we'll see what it's about to do here let me go back to vs code and let me do something like this self. name equals name and self. house equals house but I don't want to just init this object very generically I want this method called in it to take in not just self but name comma house as well now what in the world is going on because there's a lot of weird syntax here there's this Dunder init method double underscore init double underscore there's all of a sudden this parameter called self and then there's this new syntax self. name and self. house now you're seeing really a manifestation of objectoriented programming it's not all that different fundamentally from what we've been doing for weeks with dictionaries by adding keys to dictionaries but in this case we're adding variables to objects AKA instance variables to objects now what's going on let's do this in Reverse let's go back to the line of code we wrote earlier on line 15 I am treating the name of this class student with a capital S as a function and I am passing in two values name and house what I've highlighted here on the screen on line 15 is generally known as a Constructor call this is a line of code that is going to construct a student object for me using synonyms it is going to instantiate a student object for me and again how is it going to create that object it's going to use the student class as a template as a mold of sorts so that every student is structured the same every student is going to have a name every student's going to have a house but because I can pass in arguments to this student function capital S I'm going to be able to customize the contents of that object so if you think about the real world if you've ever been on a street or a neighborhood where all of the houses kind of look the same but they're might be painted differently they might be decorated a little bit differently on the outside all of those houses might have been built using the exact same blueprint sort of a mold if you will but then you can specialize exactly the finer points of those houses by painting the outside a different color or planting different trees you can style them differently similar uh in spirit here we have a student blueprint that's always going to have now a name and a house but it's up to you and me to pass in any name in any house that we want now where is this function the fact that I'm calling student capital S and then a parenthesis and a Clos parenthesis with arguments inside suggest that there's a function somewhere in the world that has been defined with def that's going to be called well as you might have guessed by now the function that will always be called by definition of how python classes work is a function called double underscore in it double underscore why it's a crazy name but it's what the authors of python chose to just implement the initialization of an object in Python now the only weird thing especially weird thing I will admit is this it would be way clearer to me too if the only two parameters for in it were just name comma house right that's how we've defined every function thus far in the class you just specify the parameters that you want the function to accept and indeed that lines up with what I'm doing on line 15 I am only passing in two things to the student function but it turns out that the authors of python need to give us a little bit of help here because suppose that you pass in name and house to this init method and a method is just a function inside of a class what are you going to do with the name in the house like literally where are you going to put them if you want to remember the name in the house for this student you've got to be able to store those values somewhere and how do you store them in the current object that has just been instantiated well the authors of python decided that the convention is going to be that this init method also semi secretly takes a third argument that has to come first by convention it's called self but you could call it technically anything you want but the convention is to always call it self and self as its name implies gives you access to the current object that was just created what does that mean again now on line 14 now that it's moved down a little bit this line here is a Constructor it constructs a student object but there's nothing in that object initially there's no name there's no house but the object exists in the computer's memory it's up to now you to store the name and the house inside of that object how do you do that well python will just automatically call this init method for you and it's going to automatically pass in a reference to a an argument that represents the current object that it just constructed in memory for you and it's up to you to populate it with values and what this means is that inside of your init method you can literally do self. name to create a new attribute AKA an instance variable inside of that otherwise empty object and put this name inside of it it allows you to do self. house and store that value of house now you could call these things anything you want they could be n they could be H as before but that's really not very self uh explanatory much better to do this kind of convention self. name equals name self. house equals house and this is like installing into the otherwise empty object the value name and house and storing them in really identically named instance variables in the object and again an object is just an instance of a class now I know that was a lot of vocabulary that's a lot of weird syntax so any questions on this init method whose purpose in life again is to initialize an otherwise empty object when you first create it so what is the difference between the init method and default Constructor a good question so in other languages if you programed before for instance Java there are functions that are explicitly called Constructors that indeed construct an object they initialize it with values python technically calls this init method the initialization method it initializes the value it's on line 14 uh line 15 now of my code if I scroll back down that I'm technically constructing the object it turns out there's another special method in Python that we won't talk about in detail today called underscore underscore new underscore underscore that actually handles the process of creating an empty object in memory for us but generally speaking you the programmer don't need to manipulate the new function it just works for you instead you define your own init method here an init function inside of your class and that method initializes the contents of the object so there's technically a distinction between constructing the object with new and initializing it within it but in the world of python you pretty much only worry about the init method python generally does the other part for you a good question others uh what about if you want to store more than one name or more than one house a good question if you want to store more than one name or more than one house you can do this in different ways you could create other attributes technically called instance variables like self. name one self. name two but we've seen in the past that that is not a very good design just to have multiple variables to store multiple things maybe instead you have an instance variable called self. names plural and you set it equal to a list of names or a list of houses now in this case I don't think that really solves the problem because I'm trying to implement a student singular so it doesn't really make sense to have multiple first names maybe a nickname maybe a last name so we could add those to but I don't think we need multiple names per se and in this case multiple houses but absolutely you could do that using some of our familiar building blocks like lists other questions how are classes or objects represented in memory how are classes and objects represented in memory so the class is technically just code it is the code on the top of my file lines one through four that defines that blueprint that template if you will um objects are stored in the computer's memory by taking up some number of bytes so you're probably familiar with bytes or kilobytes or megabytes there's some chunk of bytes probably all in the same location in the computer's memory or Ram where those V where those objects are stored but that's what python the program handles for you python The Interpreter figures out where in the computer's memory to put it you and I the programmers get to think and solve problems at this level python The Interpreter handles those lower level details for you how about one final question on classes and objects now my question is if we can the same do the same thing with the dictionary so I to use classes good question if you can do the same things as you can with dictionaries why should you use classes because we are just scratching the surface now of what you can do with classes allow me to go back now to my keyboard and show you more of what you can do with classes but in short you can do much more with classes you can ensure the correctness of your data much more with classes you can error check things and generally you can design more complicated software more effectively and we'll continue to see today features of python and object-oriented programming more generally that allows us to do just that so let me propose in fact that first let's just tighten up this current implementation which again has us with an init method that just declares two instance variables self. name and self. house which again just creates those variables inside of the otherwise empty object and assigns them values name and house respectively let me go ahead and just do one little thing here I don't really need the student variable let me just tighten this up so that each time we improve or change the code we're focusing really on just the minimal changes alone so I've not fundamentally done anything different I just got rid of the variable name and I'm just returning the return value of this student function that's constructing my new object for me so I'm just tightening things up as we've done many times in the past well what if something goes wrong when in creating this student for instance what if the user does not give us a name and they just hit enter when prompted for name like I don't want to put in my computer's memory a sort of bogus student object that has no name right I'd ideally like to check for errors before I even create it so I don't create a nameless student it would just be weird and probably a bug to have an object that has no name similarly I don't want the user to be able to type in something random as their house at least in the World of Harry Potter there's really only four houses at Hogwarts at least or there's again Gryffindor and Hufflepuff and Ravenclaw and Slytherin a list of four valid houses it would be nice if I somehow validated that the user's input is indeed in that list now I could do all of that validation in my get student function I could check is the name empty if so so don't create the student object is the house one of those four houses if not don't create the student object but that would be rather decoupled from the student itself right get student currently exists as just my own function in my student. py file but classes and really object-oriented programming more generally encourages you to encapsulate inside of a class all functionality related to that class so if you want to validate that a name exists if you want to validate that a house is correct that belongs just uh fundamentally in the class called student itself not in some random function that you wrote elsewhere again this is just methodology because again if we think about writing code that gets longer and longer more and more complicated it should make just intuitive sense that if you keep all the house and all of the Stu all of the name and all of the house related code in the student it's just better organization right keep all of the related code together and that's probably going to set you up for more success and indeed that's part of this methodology of objectoriented programming let me go ahead now and change my students classes init method to do this if the name is blank so if not name and we've seen this kind of syntax before if you say in Python pythonic if not name that's like doing something like this if name equals equals quote unquote but I can do this a little more elegantly just say if not name would be the more pythonic way to do it well I want to return an error like I might want to do something like this print missing name but this is not good enough it does not suffice to just print out missing name and then let the rest of the code go through all right well what could I do instead in the past we've seen another technique I could do cy. exit and I could say something like missing name and I could go up here and I could import CIS but this is a really obnoxious solution to the problem just because you or maybe a colleague messed up and called a fun with an invalid name you're going to quit my whole program like that's really really extreme of a response and you probably don't want to do that if your program's in the middle of running you might want to clean some stuff up you might want to save files you don't want to just exit a program sometimes in some arbitrary line just because input was invalid so I don't think we want to do that either but we do now have a mechanism for signaling errors unfortunately I can't do something like this I could try returning none and say uh this student does not exist I'm going to hand you back none instead but it's too late if we scroll back down to where I'm creating the student it's on line 17 now where I've highlighted this code the student has already been created there is an object somewhere in the computer's memory that's structured as a student it just doesn't have any values inside of it but it's too late therefore to return none that ship has sailed the object exists you can't just suddenly say nope nope there is no object there is an object it's up to to you to Signal an error and how do you signal an error well we've actually seen this before but we haven't had occasion to create our own errors it turns out in Python there's another keyword related to exceptions that python itself uses to raise all of those exceptions we've talked about in the past when you've caught things like value errors or other such exceptions that come with python well it turns out you the programmer can raise that is create your own exceptions when something just really goes wrong not wrong enough that you want to quit and exit the whole program but enough that you need to somehow alert the programmer that there has been an error something exceptional in a very bad way something exceptional has happened and let them try to catch that exception as needed so let me go back to vs code here and propose that if the user passes in an invalid name it's just empty so there's not a name well what I really want to do is this I want to raise a value error and we've seen the value errors before we've created value errors accidentally before and generally you and I have tried to catch them if they happen well the flip side of this feature of exceptions in a language like python is that you the programmer can also raise exceptions when something exceptional happens and you can even be more precise you don't have to raise a generic value error and let the programmer figure out what went wrong you can treat value error and all exceptions in Python like functions and actually pass to them an explanatory message like quote unquote missing name so that at least the programmer when they encounter this error knows oh I messed up I didn't make sure that the user has a name and now what do you want to do instead well now if you're the programmer you could do something like this you could try to create a student except if there's a value error then you could handle it in some way and I'm going to wave my hand with a dot dot dot at how you would handle it but you would handle it using try and accept just like we have in the past and that would allow you the programmer to try to create the student but if something goes wrong okay okay I'll handle it nonetheless so what's new here again is this raise keyword that just lets you and I actually raise our own exceptions to Signal these errors well let me go back to my code here and I'm just going to go ahead and not bother trying or catching this error for now we'll just focus on raising it and assume that from our week on exceptions you could add try and accept as needed in places let me go back to the code here and propose that something else could go wrong with house right if there is a name we're good but if we're given a house but it's invalid we should probably raise an exception for that too so what if we do this if house is not in the list containing Gryffindor quote unquote uh Hufflepuff quote unquote uh let's see Ravenclaw quote unquote or uh Slytherin quote unquote then with my colon let's ra raise another type of value error but rather than raise a generic value error let's pass in an argument quote unquote invalid house and so here we now see a capability that we can do with classes that we can't with dictionaries if you add an attribute to a dictionary a key to a dictionary it's going in no matter what even if the name is empty even if the house is a completely random string of text that's not one of these four houses it's going into that dictionary but with the class and by way of this init method you and I can now control exactly what's going to be installed if you will inside of this object you have a little more control now over correctness and so now let me go ahead and uh scroll back down to my terminal window and clear it let me run python of student. let me type in something like Harry let me type in Gryffindor enter and we see that indeed Harry is from Gryffindor what if I made a mistake though what if I ran python of student. and typed Harry as the name but at this time typed in number four Private Drive which is where he grew up instead of his proper Hogwarts house let me hit enter now and now you see a value error but this isn't one that python generated for us per se I raised this error and therefore if I went in and wrote more code in my get student function I could also catch this error with our usual try except syntax so all we have now is not just classes in our toolkit but even more Powers when it comes to exceptions and not just catching them ourselves but raising them ourselves too any questions now on this use of class isn't in it and now this ability to raise exceptions when something goes wrong inside of the initialization so what if user has a middle name name middle name and last name how would you fix that a good question if you wanted the user to if you wanted the student to have a first name middle name and last name we could do this in a bunch of different ways the simplest though if Let Me Clear My screen here and let me just temporarily do this let me propose that the init method take in a first argument a middle argument and a last argument and then what I think I would do down here is ultimately have first equals first and then I would do the same thing for middle and last so middle and middle and then last and last and then what I would have to do here is when I actually ask the user for their name I might need to really go all out I might need to ask them first for their first name and store that in a variable called First and therefore pass in first I might similarly need to ask them for their middle name and store that in a variable and then pass in a second argument middle and then lastly if you will let me go ahead and create a third variable called last get the input for their last name and pass that in as well I could instead just use one input and just ask them for their whole name so type in David uh ma enter or David J me all three of them and maybe I could use Python split function maybe a regular expression to tease it apart that's probably going to be messy because there's going to be people who don't have just two or three names they might have four or five so maybe sometimes it's better to have multiple prompts but that's not a problem because with a class we have the expressiveness to take in more arguments if we want we could even take a list if we wanted but I think we'd probably want to have even more error checking then not just for name but for first and then maybe for middle and then maybe for last so it just is more and more code though there would be ways to perhaps consolidate that too let me undo all of that and see if there are other questions now on classes I assume this is classes are something I might do at the beginning of a project can I just put them in a different file and import them into my project or or or my main code as needed absolutely a really good question you could imagine wanting to use this student class not just in studenty but in other files or other projects of yours and absolutely you can create your own library of classes by putting the student class in your own module or package per our discussion in the past about libraries more generally and absolutely you can do that and later today will we see that we've actually been using classes you and I before in thirdparty library so you too can absolutely do the same how about one more question on classes can you have optional variables in classes and two can you have your own error names like let's be egotistic and say I when AR raise Eric eror short answer yes so you can uh these init functions are just like python functions more generally even though they're special and that they're going to get called automatically by python 4 you but if you wanted to make house optional you could do something like this you could give it a default value in the init functions uh signature so to speak in that first line of code on line two and that would allow me to not have to pass in house in this case I'm going to continue to always pass in name and house but you could make things optional and yes to your second question if you wanted to have your own error message like an Eric error you could actually create your own Eric error exception and we'll see in a little bit that there's actually a whole Suite of exceptions that exist and you too can invent those as well let me propose though that we now introduce one other aspect of this whereby we try printing out what a student looks like at the moment if I scroll back down to my main function I'm still printing the student's name and house very manually I'm going inside of the object doing student. name and I'm going inside of the object again and getting student. house just to see where uh the student is from but wouldn't it be nice if I could just print the student like I've been printing for weeks any int or float or stir or any other data type well let's see what happens if I just try printing the student instead of manually going inside and trying to create that sentence myself well in my terminal window let me go ahead and run python of student. py again let me type in Harry let me type in Gryffindor and we voila Harry whoa okay main student object at o x102 733 e80 well what is going on well if you were to run the same code you might actually see something different on your computer in terms of that number but what you're really seeing is the underlying representation as a string of this specific object in particular you're seeing where in the computer's memory it is this number o x102 733 e80 refers to essentially a specific location in the computer's memory or Ram that's not really that interesting for me or you or generally speaking programmers but it's just a default way of describing via print what this thing uh is but I can override this as well it turns out that there are other special methods in Python when it comes to classes not just underscore underscore in it uncore underscore But continuing in that same pattern underscore uncore stir underscore underscore so this too is a special method that if you define it inside of your class python will just automatically call this function for you anytime some other function wants to see your object as a string print wants to see your fun your object as a string but by default if you don't have this method defined in your class it's going to print out that very ugly esoteric Incarnation thereof where it says main. student object at Ox dot dot dot well how can I then Define my own stir function well here back in VSS code let me propose that I go in and Define not just underscore underscore uh in it but let me Define a second function in this class here as follows def underscore underscore stir underscore underscore there are indeed two even though the font in VSS code is putting the two underscore so close it just looks like a longer underscore there are indeed two there on the left and the right just like for in it this one only takes one argument that by convention is always called self so that you have access to it and then indented below that after a colon I'm going to go ahead and create a format string and return it so let me go ahead and return how about something generic first like a student so I'm not going to bother even trying to figure out what this Student's name or house is I'm just going to always return a student let me go back now to my earlier code which has print student on line 16 Let Me Clear My terminal window and rerun python of student upy enter type in Harry type in Gryffindor last time I saw that very cryptic output this time I see more generically a student you know more readable but not very enlightening which student is this well notice that the uh double underscore stur method takes in this self argument by default it's just the way the python authors designed this method it will always be passed a reference to the current student object what do I mean by that when this line of code on line six is called print because it's hoping it's going to get a string is going to trigger the underscore uncore stir underscore uncore method to be called and python for you automatically is going to pass into that method a reference to the object that's trying to be printed so that you the programmer can do something like this here's an F string with double quotes as usual I'm going to use some curly braces and say print out self. name name from self house so there's nothing new in what I've just done it's just an F string an F on the beginning two double quotes a couple of pairs of curly braces but because automatically this stir method gets past self so to speak a reference to the current object I can go inside of that object and grab the name I can go inside that object again and grab the house so now when I go back to my terminal window previously it just printed out a student but but now if I run python of student. py enter type in Harry type in Gryffindor and one more time hit enter Harry is again from Gryffindor but if I run this yet again let's for instance do Draco is from Slytherin enter Draco from Slytherin now it's customized to the specific object that we're trying to print questions on this function here this thunder stir method is there anything else that the uncore uncore stir method can do um the other question is what's the difference between stir and repper a good question so there are many other methods that come with python classes that start with underscore underscore we're just scratching the surface and we'll pretty much Focus primarily on these but yes there are many others and we'll see at least one other in just a little bit there is an among the others is indeed one called uh repper which is a representation of the Python object generally speaking the _ uncore rcore uncore method is meant for developers eyes it typically has more information than Harry from Gryffindor it would also say what type of object it is like a student capital S whereas underscore uncore stir underscore uncore is generally meant for users uh the users of the program and it's meant to be even more userfriendly but both of those can be overridden as you see fit well let me propose now that we pick up where we've left off on student and just add even more functionality but not just these speci methods like double underscore init and double underscore stir like let's create our own methods because there in lies the real power and flexibility of classes if you and I as the programmers can invent new functionality that's specific to students for instance uh students at Hogwarts over the time in in school learn how to cast a certain type of spell so when they say expecto patronum something comes out of their wand that typically resembles an animal or something like that it's a special spell that they have to practice and practice so let's see if if we can't store not just a student's name and their house but also their Patronus what actually they conjure when using this spell well let me go ahead and clear my terminal window and in the top of my code here in the init method of student let me go ahead and start expecting a third argument in addition to self which automatically gets passed in called petronis and I'm not going to worry uh for now on validating the petronis from an official list of valid patronises or petroni I'm instead going to go ahead and just blindly assign it to self. Patronis equals petronis and we're going to let the user type whatever they want for now but I could certainly add more error checking if I wanted to limit the patronises to a specific list of them here let me go ahead now and prompt the user for this petronis as by in my get student method uh get student function defining a variable called petronis or anything else prompting the user for input for their petronis and now I'm going to go ahead and pass in that third variable here so again similar in spirit to just adding more and more attributes to the class I'm going to pass in all three of these values instead of just two I'm not going to do anything interesting with that value yet but just to make sure I haven't made things worse by breaking my code let me run python of studenty I'll type in Harry I'll type in Gryffindor and it turns out his Patronis was a stag and hit enter I haven't seen what his Patronus is in my output because I didn't change my stir method yet but at least I don't have any syntax error so at least I've not made anything worse but suppose now I want to have functionality not just for initializing a student and printing out a student if my class is really meant to be a student what I can do is not just remember information about data about students what's powerful about classes unlike dictionaries alone is that classes can have not just variables or instance variables so to speak those attributes we keep creating they can also have functions built in AKA methods when a function is inside of a class it's called a method but it's still just a function at this point we've seen two functions already two methods called uh double underscore init and double underscore stir but those are special methods in that they just work if you define them python calls them automatically for you but what if you wanted to create more functionality for a student so that your class really represents this real world or maybe fantasy world notion of a student where students not only have names and houses and patronises they also have functionality they have actions they can perform like casting a charm a spell magically could we Implement therefore a function called charm that actually uh uses uh their magical knowledge well let's go ahead and Define our very own function as follows Let Me Clear My terminal window scroll back up to my student class and instead of creating yet another function that's special with double underscores I'm going to invent my own function or method inside of this class I want to give uh Harry and Hermione and and all of the other students the ability to cast charms so I'm going to define a function that I can completely on my own called charm I could call this function anything I want but because it's a method inside of a class the convention is that it's always going to take at least one argument called self by convention so that you have access to the current object even if you don't plan to use it per se all right let me go ahead and propose that we Implement charm in such a way that the method returns an emoji that's appropriate for each student's petronis all right how to implement this well inside of the charm method let's go ahead and match on self. Patronis which is the instance variable containing a string that represents each student's Patronis and in the case that it matches a stag for instance for Harry let's go ahead and return maybe the closest Emoji this horse here how about in the case of an otter well in that case let's go ahead and return oh maybe the closest match to the otter which might be this Emoji here and let's see in the case of a for Fon rather than Herm a Jack Russell Terrier let's go ahead and return how about don't have as many options here why don't we go ahead and return the cutest available dog in that case and in the case of no Patronis recognized as might cover someone like Draco let's go ahead and use a default case using the underscore as as in the past and let's go ahead and return for this oh what should happen if someone doesn't have a petronis why don't we just see a magical wand that seems to fizzle out as in this case all right well now rather than just print the student let's go about printing their actual Patronis so I'm going to go down to my main function here I'm going to still get a student using the get student function but rather than print student let's go ahead and declare expecto patronum printing out just that as pure text and now let's go ahead and print out not the student but rather the return value of their own charm Method All right so let me go back down to my terminal window and run python of student. py and enter name let's start with Harry he lives in Gryffindor uh petronis is a stag and let's see expecto patronum and of course we see the Stag emoji what about someone like Draco who at least in the books doesn't have a known petronis well let's go ahead and clear my terminal window rerun python of student. and this time let's type in Draco for name Slytherin for house and Patronis is unknown so I'm just going to go ahead and hit enter and now expect o patronum and just kind of sizzles instead questions now on what I've done by implementing this charm method can we uh like call a method outside the function absolutely and we're seeing that already if I scroll back down to my main function which is outside of the class because it's all the way down in the file it's all left align just like the class notice on line 28 I'm calling student. charm and I'm accessing a method that's inside of the student object even though my main function is outside of the class and what's different between our init function or method and our stir method that we've seen before those are called automatically when you try to create a student or when you try to print a student for the first time we're now seeing a method that I invented inside of the student class that I can call anywhere I want and if I'm calling it outside of the class like I am here I just use the name of the variable containing that student object and I just do charm just like I could access the individual attributes or in instance variables inside of that object as well other questions on classes and this new method charm in a parentheses you are you put self supposed to be like a initializer but like in the top part you didn't you didn't um Define it the same way would you have to put the class on why you didn't put the class right there so notice the indentation here so on line one I've of course said class student colon and then everything below that is indented at the moment that means that my init method my my stir method and this new charm method are all inside of part of that class by convention then each of these methods inside of a class should expect that python will automatically pass in at least one argument to every method in a class and that argument will always be a reference to the current object the Harry object or the Draco object that is currently trying to cast a charm or be printed so whenever you create a method inside of a class you should always have it take at least one argument called self and then zero or more other arguments that are entirely up to you in it for instance takes three more name house Patronis stir takes zero more charm takes zero more but the convention is to always call that default argument self and python just automatically gives you access to the current object other questions how about one more on classes and charms sir I just wanted to ask that uh you you have put the emojis in double quotes So does it take the Emojis as a form of strings or something else yes if unfamiliar an emoji is just a character it's part of a mapping of numbers to letters known as Unicode and so whenever you see these emoji on the screen like the horse or the otter or the dog here specifically that's really just like a key from your keyboard you and I on Max and PCs can't typically type it because you see English characters or some other human language but Emoji are increasingly available uh via menus and drop down and in my case copy paste on Macs and PCs and Android devices and iPhones they are just characters even though they look like pictures you can think of it like a graphical font almost so they're just text and indeed if you put them between double quotes or single quotes you can print Emoji just like you can any other human character as well well let me propose now that we remove this Patronis code just to simplify our world and focus on some of the other core capabilities of classes so at the risk of disappointing I'm going to get rid of all of these beautiful emoji and charms and I'm going to go ahead and stop asking the user now for their petronis and I'm going to stop passing it into in it here and I'm going to stop uh doing this here and I'm going to instead just go ahead and restore our use of print student here and I'm going to go ahead and get rid of petronis down here so essentially undo all of the fun charm we just created so we're now back at the point in the story where we have a student class with only two methods in it and stir the first of those takes of course self as the first argument as it always will plus two more now name and house no more Patronis we're validating name up here we're validating house down here and then we're assigning name and house respectively to two instance variables called name and house also but we used self to get access to the current object to store store those values therein we then still have our stir method here which takes one argument by default self and that's it and that function is going to be called automatically anytime you want to convert a student object to a string just like print might want to do here so let me go ahead and just make sure I haven't broken anything let me run python of studenty I'll type in Harry I'll type in Gryffindor enter okay we're back in business gone are the charms and patronises but at least I'm back to a situation where I have names and houses but it turns out at the moment our use of classes is not very robust even though we have this mechanism very cleverly if I may in our init method of making sure that we're validating name and house making sure that name is not blank and making sure that house is a valid house among those four Hogwarts houses it turns out that classes will still let me get at those attributes those so-called instance variables using notation anyway let me scroll down then and try to do this a little adversarially suppose that on line 16 I go ahead and call get student which exists as before and then I store the return value in a student variable again on line 16 that will ensure that get student gets called which calls input and input and then it calls the student Constructor which invokes automatically this init method so by way of how we've laid out my code we're going to ensure that name is not blank and house is definitely one of those four values my error correction or error checking is in place but if I'm a little adversarial I can still circumvent it suppose that fine I'm G to you're going to require me to type in Harry and griffindor I'm going to go ahead and type in student.h house equals quote unquote number four private drive and you're not going to be able to stop me why well it turns out with classes and objects thereof you and I can still access those instance variables using this familiar dot notation that's how we began the story of classes just setting these attributes ourselves but you can also read these attributes themselves and change them later if you want and this will effectively circumvent the if condition and the other if condition in our init method because that is only called when you first create the student object there's nothing stopping me at the moment from just changing the house or the name after so if I now now clear my terminal window and run python of studenty I'll still type in Harry and Gryffindor to meet my requirements that the house be one of those four but when it's printed notice I've still overridden it so it seems that while classes do allow us a little more control over the data we're storing it doesn't necessarily prevent the user be it or rather the programmer be it myself or maybe a colleague from still kind of messing things up so here too in the spirit of programming a little more defensively allow me to introduce another feature of python as well namely properties so a property is really just an attribute that has even more defense mechanisms put into place a little more functionality implemented by you to prevent programmers like me and you from messing things up like these attributes so again a property is going to be an attribute that you and I just have more control over how we just write a little more code using some python conventions and how we're going to do that is going to use in just a moment a feature a keyword known as app property which is technically a function property is a function in Python but we're about to see some new at syntax that allows you to decorate functions and this to is a term of Art in the world of python you can have decorators which are functions that modify the behavior of other functions if you will and we'll leave it at that without going too much into the weeds and we'll see by example how you can use these decor Ator specifically to define properties so let me go back to vs code here and let me propose that I do this I'm going to go ahead and create how about a property called house as follows inside of my uh student class I'm going to go ahead and below my init method and below my stir method I'm going to go ahead and Define a function called house that takes as it always must one argument at least called self and what I'm going to do now is return uh self. house so I'm just going to define a method called House whose sole purpose in life is to return the value of house but I'm going to Define one other method curiously also called house but that's going to take into as arguments two values self as always and also a value called house and I'm going to now do this uh I'm going to say self rather I'm going to do self. house equals house now what have I done well let me just temporarily add some comments here in a moment we're going to start referring to this generally as a getter and down here I'm going to refer to this as a Setter and this is terminology you frequently see in the world of java if some of you have programmed in Java before but as the names imply a getter is a function for a class that gets some attribute a Setter is a function in some class that sets some value and now even though we're not done and there's a bit of a mistake in the code I've already written intuitively what we're going to do is this we're trying to prevent programmers myself included from circumventing my error checking that I put into place for name and house how can I do that well we don't have that many building blocks in programming we have things like variables for data and we have functions for actions well why don't we do this why don't we somehow require that in order to access an attribute you go through some function and let's require that in order to set some attribute you go through some function and conventionally those functions are called a getter function and a Setter function and why are we using functions or in this case methods inside of a class well once you have functions those are just actions or verbs that you and I can create ourselves we can put any error correction I want in these functions because it's code that's going to get executed top to bottom so so how can I now prevent the user from setting the house to an invalid value let me borrow some logic from before rather than blindly do this just set self. house equal to the house value that's passed in let's add our eror checking there so if house is not in the following list of Gryffindor or Hufflepuff or slyther or Ravenclaw or slythering in just as before let's go ahead and raise a value error just to signify that uh-uh something has gone wrong I'll be more explicit I'll include a message like invalid house quote unquote otherwise I'm going to proceed on now line 21 to set self. houseo house so I've just copied if you will or retyped my error checking inside of this so-called Setter function now why have I done that well to be clear whenever the user or the programmer writes code like this student. housee equals what's about to happen magically is python will not just let the programmer access student.h housee directly that attribute that instance variable AKA self. house it's instead going to magically automatically call this Setter function for me how does python no to do that well if it sees that on the leftand side there is self. housee where house is the name of the getter or Setter and then it sees an equal sign indicating assignment that's just enough of a visual clue to say wait a minute I'm not going to let you access that attribute directly I'm going to use the setter instead why because the equal sign means I'm trying to set I'm trying to assign a value from right to left into that attribute so what Python's going to do automatically is call this function for me and that's amazing because now I can execute code an algorithm to check do I want to let the user the programmer set that attribute to that value if not I'm going to raise a value error and you're just not going to be able to do it if so fine I'll go ahead and set it for you but in order to do this we need a little more syntax and I'm going to get rid of my comment and I'm going to use that decorator I need to tell python to treat this method as a getter and then the Syntax for the setter is a little different you now say house. Setter I wish one was getter and the other was Setter that's not the way they designed it when you want to define a getter you just say at property above the function and you name the function exactly like you would like the property to be called quote unquote house once you do that you can now use a new decorator that sort of automatically created for you called at house because I called it house and then you literally say at house. Setter and this whole line on line 17 is a clue to python that here comes a function whose name is identical but notice that it takes two arguments both self so you have access to the contents of the object and house which is just going to be a stir that comes from the programmer from like the human input return value so that you can set that value as well but there's one fix I need to make now here everything else I think is still good however watch this I no longer need this error check here why because if I scroll back down to my code here I claimed a moment ago that code like this with uh student.h house equals is going to automatically get python to call my Setter for me guess what even up here in my init method calling self. housee equals is also going to call my Setter method which is amazing because now I can keep all of my error checking in one place in the setter and it will now get called either E when I create the object for the first time because of in it or even if the you the programmer tries to circumvent that init method and change the value of this attribute my Setter will also get called my Setter will get called anytime I access do house but there's one fix I need to make unfortunately I have collided names right now if we go up here on line five this is an instance variable it's a string inside of myself inside of the current student object called name and this is another instance variable called House unfortunately if I have an instance variable called name and house I cannot also have functions called house they're going to collide you got to decide do you want the variable to be called house or do you want the function to be called House unfortunately you can't have both because now Python's going to confuse one for the other so the conventional fix for this is to do this to have the setter not store the value that's passed in in self. house but to use an almost identical name but to use a little indicator that you means you know you're doing this correctly you typically by convention put an underscore in front of the instance variable's name and when you return it up here you similarly put an underscore so now technically my instance variable is called underscore house but my property which is a fancier attribute if you will is called house alone huge amount of syntax I know but it's a very powerful feature and again this is why you can graduate from dictionaries alone and have so much more functionality at your disposal let me go ahead and clear my terminal window and run python of student. enter name all right let's go ahead and type in Harry let's go ahead and type in Gryffindor crossing my fingers as always and now look inval house this is a good thing why because notice in my main function I'm still trying maliciously if you will to change Harry's house to not be one of the four valid ones I'm trying to change it to his childhood home of number four private drive but because python knows that wait a minute you're trying to assign that is set a value and that value AKA house is now defined as a property you're going to have to go through the setter function instead to even let you change that value and because I have this raise value error if the house is not as intended you're not going to be allowed to change it to an invalid value so I'm protecting the data on the way in through the init method and I'm even defending the data if you try to override it there so I think the only solution for me the programmer is don't try to break my own code let me remove that line because it's just not going to work let me run python of studenty and again type in Harry type in Gryffindor enter and Harry is indeed from Gryffindor if I did something incorrect like Harry from number four Private Drive enter we're again going to see the value error because my code just doesn't let that value in Via manual input now or via that adversarial change all right that was a lot but any question on properties uh while we are using gets and Setters it's just for the purpose so that we can find that um that fun that method that function in in our code the reason that I'm going through the trouble of defining this getter or Setter is because I want to make sure that programmers cannot do things like this if I'm going through the trouble of validating the attributes for these student objects I don't want you to be able to go in there and just change them at will I want to have some control over that object so that you can just trust that it's going to be correct as designed so using a getter and Setter really just enables python to automatically detect when you're trying to manually set a value the equal sign and the dot as I've highlighted here is enough of a clue to python to realize wait a minute you're trying to set a value let me see if this class has a Setter defined and if so I'm going to call that and I'm not just going to blindly assign the value from right to left so it's just giving me more control other questions on properties when we use a gets we just have just one argument and if we use Setters is always going to be two arguments is that normal correct it's always going to be one argument self for the getter two arguments for the setter self and something else and the intuition for that is if you're getting a value you don't need to pass anything else in because you already know the object it's called student in this case so you're just going to get the value of that property but if you want to set the property to something else you got to pass in that argument you've got to pass in the value to which you want to set it so it's always zero or one however you see it as one or two because again any function inside of a class AKA a method is going to be automatically passed self so that you have access to that current object in memory how about one other question on properties why didn't we use the same underscore house in init meod a good question so even though I'm using the underscore house here in my Setter and the underscore house here in my getter I deliberately did not use it up here the reason for that is that by using self. house and this equal sign that's the same pattern that I want python to recognize I want python to automatically call the setter even when I'm passing in the house via the init method if I were to change this to do this that would circumvent the setter and now there's no error checking in in it whatsoever so it's such a fine line the only thing standing between us and error checking or no error checking is the presence or absence of this underscore but that's typically the convention by not using the underscore there make sure that even that assignment goes through the setter so that honestly I don't have to copy paste the same error checking in two places I can put it just in the setter so it's better design and that's why I manually retyped it at first but then I deleted it from in it well allow me to propose that we make one other change to this file might as well go ahead and Define a property for name as well and let me go ahead and do this maybe above the house property just to keep things uh in the same order as I defined them earlier let me give myself another property this one's going to be called name it's going to take one argument called self as always and this one very similarly is just going to return self. uncore name so I'm going to anticipate that I'm going to have to rename name also so that I don't have that same Collision as before but now let me go ahead and Define another uh setter this one for name so the convention is at name. Setter why name because the property I just created is called name so the getter and Setter sort of work in conjunction in that in this way if you will let me go down under ATN name Setter and Define another function also called name but the key thing here is that it's not identical it's not the exact same function name and the exact same number of arguments the setter again takes a second argument and I can call it anything I want but I'm going to call it name because that's what's being passed in and I'm going to air put my error checking here if not name just like we used to do let's go ahead and raise a value error and let's put an explanatory message like uh Missing name quote unquote otherwise let's go ahead and update self. uncore name to equal name and I don't have to change in it except to get rid of this duplicate error checking now because again if I use self. name equals here and self. house equals here with no underscore for both of those assignments are going to go through my two Setter functions now before we run this let me go ahead and remove this adversarial code which we know won't work because we're catching it let me go back down to my terminal window and run python of studenty enter let's type in Harry let's type in Gryffindor and that seems to work let's try though again to run python of studenty with Harry from number four privet drive this will not work a value error with invalid house because that's not one of the four WS houses and now for good measure let's run it one more time and let's not even give it a name let's just hit enter when prompted I can type anything for the house I'll go ahead and still give it Gryffindor enter now we get another value error but this one is for missing name so we seem now to have all the more of a defense mechanism in place to ensure that name is as we expect it's got to have some value that's not blank and house is as we expect it's got to have one of those four values but at the risk of bursting everyone's bubble and making you wonder why did we just go through all of that unfortunately python really focuses on conventions not hard constraints and by that I mean this if I go back into my main function after I've gotten a student online 30 and I try to adversarially do something like this student. housee equals quote unquote number four Private Drive we know this won't work because my Setter for house is going to catch this watch again again python of studenty uh let's type in Harry let's type in Gryffindor which will at least pass our check that's induced by in it but line 31 is going to trigger the same Setter to be called and we're going to raise a value error saying invalid house unfortunately and if some of you are already thinking a little adversarially tragically look what you can do you can change house to beore house why well the instance variable is now called underscore house the property is called house no underscore but the underlying attribute implemented as an instance variable is still called underscore house and tragically python of student. let's type in Harry let's type in Gryffindor which is correct but Watch What Happens now oh my God we slip through so what was the point of all of this emphasis from me on doing things the right way the python iic Way by having this getter and Setter well unlike languages like Java that just prevent you from doing things like this python itself allows you to specify that certain instance variables can be public and accessible to anyone's code or protected or private which means that no one else should be able to change these values in the world of python it's just the honor System it's not baked into the language itself that there's a notion of visibility public or private or even somewhere in between protected instead you're on the honor system and the convention generally is if a instance variable starts with an underscore please don't touch it like just don't like that's on you if you touch that variable and break things the underscore is meant to signify a convention that this is meant to be private but it really just means please don't touch this sometimes if there's two underscores which you can use two that's an even greater effort by programmers to say really don't touch this but technically speaking there's nothing stopping you or me from circumventing all of these mechanis Ms these properties these Getters and Setters were ultimately just on the honor System not to do so when we see instance variables prefixed with one or perhaps even two underscores all right so this is a lot all at once this introduction to object-oriented programming but it might come as quite a surprise that even though we might had have identified oop by name in weeks past we've all been using classes and objects for weeks now in this class in fact if you think back on one of the very first things we did in this class we used integers and just got integers from the user but if you haven't already if you go and dig into the documentation for integers which again lives at this URL here you would actually find that int itself is and has been for weeks a class and in fact this is the signature of the Constructor call for an INT whereby you pass in X like a number quote unquote 50 or quote unquote something else you pass in optionally the base 10 for decimal two for binary or anything else and that int function will actually return to you all this time an object of type int that is to say int is a class it is a template a blueprint for creating integers in memory and anytime you and I have converted a string for instance to an INT you and I have been creating an object of type int that was calling apparently the underscore underscore in it underscore underscore method that someone else the authors of python wrote to give us back that proper integer besides that if you can believe it stirs strings in Python have been classes since the first week of this class as well if you look up the documentation for a stir which lives at a similar URL there you will find that when you instantiate that is create a stir it takes optionally a parameter called object here the default value of which is just quote unquote which allows you to create in effect an empty string a blank string string if you will but anytime you and I have created stirs or even used explicitly this stir function you are getting back an object of type stir anytime you and I have forced a string to lowercase per the documentation using syntax like this you and I have been taking an object of type stir and forcing it all to lowercase by calling a method called Lower a method that the authors of python built into the stir class but it's been there from the gecko so this notion of method is not even new today you would have been doing it for this long if you've ever called strip to remove the leading and the trailing Whit space from a string in Python you are calling another method that came with python written by the authors of python and even though we didn't call it a class at the time a stir all this time has been a class and instances of strings are themselves objects and those objects come therefore with these functions built in AKA methods that allow us to do things like force to lowercase and strip Whit space from the beginning and end let's do another list anytime you've created a list either uh either syntactically with square brackets or literally with l i s open parenthesis closed parenthesis which is also possible you have been using a class if you go to the documentation for list at this similar URL here or more specifically the tutorial on lists here in Python you will see that a list is and has been since the early weeks of this class A Class itself and that clist class takes as part of its uh initialization in optional iterable something that can be iterated over like one comma 2 comma three or some list of values and you can then get back a list containing those same iterable values if you've ever appended something to a list in this class as I have myself in the past you've been using a method called aend that comes with the list class that per the X takes an argument that allows you to append something to the current list AKA self in the context of that method we can do this all day long if you've used a dictionary or a dict in Python I've actually all this time been calling them dict objects and that's for a reason dict itself is a class in Python if you pull up its official documentation here and you'll see that it is defined indeed as itself a class and that class comes with methods as well and so anytime we've manipulated dictionaries we've been in underneath the hood using all of those same methods and in fact we can see this if we're really curious let me go back over here to VSS code and let me go ahead and create a new file that very simply does something like play around with data types and let me go ahead and create a new file for instance called say uh type. piy just so that I can poke around inside of some values and in type. pi I'm just going to go ahead and do this I'm going to print out whatever the type is of say the number 50 and this is a function you've not necessarily seen me use already and it's not one you would frequently use in your own code there are other ways to te detect if you need to what the type is of a variable but in this case type of 50 is just going to tell me and then print out what the data type is of that value now hopefully all of us could guess that 50 is indeed going to be an integer that is an INT but we can see it in this way and this too is what's powerful about knowing a bit of programming if you want to know the answer to a question just try it out like am here so let me go ahead and run python of type. py enter and there it is when you print out the type of the number 50 you'll see on the screen in this cryptic syntax class quote unquote int this is not something that you probably want to show to the user but if you yourself just want to poke around and see what's going on or maybe use that information somehow it's certainly at your disposal to use with this type function for that let's change it around a little bit instead of passing is the argument to type 50 as an INT let's type something also familiar like hello comma World in double or single quotes let me go back to my terminal window clear the screen and run python of typey again and now voila there it is all this time a stir is also a class we can do this a few more times for instance let's go ahead and change hello world to just an empty list open square bracket close square bracket and this is starting to look a little cryptic but again notice what I'm doing in square brackets is an empty list we've done that before that is the sole argument to this new type function and that's just being passed to the print function so that the return value of type is the argument to print so if I now run this code python of type. piy there it is a list is a class two you might recall that I said that you can also create an empty list by literally doing list open parenthesis close parenthesis this is a bit of an inconsistency as we can now identify that int and stir and Now list they're technically all lowercase and I went to Great Lengths of creating my student class to have that capital S that's a convention because int and stir and list and others come with python they decided to make their built-in data types even though their classes all lowercase but the convention the recommendation in the python Community when creating your classes is indeed to capitalize the first letter as I did in something like student capital S but list open parenthesis closed parenthesis is identical to really just two empty square brackets if I clear my screen and run type dopy again you see the exact same thing the class is called list let's do one more let me change list to be not square brackets but curly braces we've done this before anytime I've done two curly braces with nothing in between this of course is an empty dictionary or a dict object in Python well we can see that now let me clear my screen run python of type. enter and there it is class dick it's been there this whole time we just didn't call it a class until today I can similarly do this one explicitly instead of two curly braces let's write out dict with two parentheses now we have a lot of parentheses again like with list but this is just making even more clear that the type of a dict object is indeed the class dict itself so this is to say that as new as a lot of today's ID and syntax might be you've actually been using it perhaps unbeknownst to you for weeks now we now just have terminology to describe what it is we've been doing all this time and you now have the expressiveness with some practice to create your own classes inside of which are your own instance variables perhaps wrapped with those properties and your own instance methods but it turns out there's other types of methods in the world thus far I've been deliberate in calling all of our variables instance variables and all of our methods uh instance methods it turns out there's other types of variables and methods out there and one of those is called class methods it turns out that sometimes it's not really necessary or sensible to associate a function with objects of a class but rather with the class itself an instance or an object of a class is a very specific Incarnation thereof again on that neighborhood that has a lot of identical looking buildings but they're all a little bit different because of different paint and such sometimes times you might have functionality related to each of those houses that isn't distinct or unique for any of the houses it's functionality that's going to be exactly the same no matter the house in question same in the world of object-oriented programming sometimes you want some functionality some action to be associated with the class itself no matter what the specific objects own values or instance variables are and for that we have a keyword called at class method this is another de cator really another function that you can use to specify that this method is not by default implicitly an instance method that has access to self the object itself this is a class method that's not going to have access to self but it does know what class it's inside so what do I mean by this well let me go back to VSS code here and let me propose that we create a new file this time implementing the notion of a the Sorting Hat from the World of Harry Potter as well to stay on theme I'm going to go ahead and run code of hat. py and in hat. py let's implement the notion of this Sorting Hat if unfamiliar in the books and in the films there is literally a pointy hat that when a student put it on their head that Sorting Hat so to speak decides what house the student is in whether it's Gryffindor or something else so let's Implement and code this notion of a Sorting Hat such that when we pass to the Sorting Hat the name of a student like quote unquote Harry this Sorting Hat implemented in code will tell us what what house that student should be in all right well let's go ahead and do this in hat. py first let's go ahead and define a class called hat and then let's get back to implementing it itself and I find this to be a helpful technique not just with teaching but when writing code like I know I want a ha class I don't necessarily know what I want it to do yet so I'm going to create this sort of placeholder dot dot dot so I'll come back to that let's now try to use this class as though it existed and from there I perhaps can realize exactly what functionality that class needs to have to support my use case let me go ahead and create a variable called hat in all lowercase and instantiate a hat object so no matter what the Hat class ends up looking like this is the common Syntax for instantiating an object of a certain class in the past we saw student all lowercase equals Capital student open parenthesis closed parenthesis and then eventually we added in things like name and house for now let's assume that the hat is much simpler than a student and it only has sorting capabilities so I'm not going to even pass any arguments there too indeed let me assume that the Sorting Hat has one Function One method inside of it called sort and so if I do hat. sort quote unquote Harry let's propose that that prints out what house that student should be in so that's it I'm going to encapsulate that is tuck away inside of a hat class all of this requisite functionality and I'm going to print out on the screen what hat uh what house Harry belongs in all right now I think I need to get into the weeds of actually initializing this class well let me go ahead and do this if I don't care to parameterize hat I just want to for instance uh sort values let's go ahead and Define this function sort first so let's define sort as taking a first argument self which is always going to be the case when defining an instance method as before but the sort method clearly takes one argument from the programmer me namely the student's name and again we've seen this dichotomy before even though I'm trying to pass in one argument when I Define the method it's got to take that many arguments plus one more self which is always going to be automatically passed in by python first all right what do I want to do well let's go ahead and do something like this uh print quote unquote or rather print this name how about quote unquote is in quote unquote some house I'm going to again use some placeholder code for myself because I'm not quite sure how to finish implementing this Sorting Hat but I think that's enough to just test where my code is at now let me go ahead and run python of hat. py and hit enter and it looks like indeed Harry is in some house we're not done yet because it's clearly not doing anything interesting but it at least is running correctly with no errors well let's go ahead now and decide where uh what house Harry should actually be in by introducing a bit of Randomness and choosing a house randomly well I can do this in a few ways let me go ahead and do this I need to have a list of houses somewhere so where can I put that I could solve this problem in different ways let me propose that I do this let me Define a method called in it as I've done before that takes in self but no other arguments and whenever the Sorting Hat is instantiated let's do this let's create a houses instant variable plural that equals this list Gryffindor comma Hufflepuff comma uh Ravenclaw comma Slytherin so the exact same list that we've used before and I'm storing it in an instance variable inside of this class I'm not taking any arguments Beyond self in it but I just need this list of values somewhere for instance so what can I do here well let me go ahead and replace some house with the actual house well what could I do here well I want to put a house there well let's go ahead and create a variable called house and if you think back to our discussion of libraries in the random module there is a function called choice that if you pass in a list of choices like self. houses that will pick a random house out of those four and then on line seven I can pass it in if I want to tighten this up let me just go ahead and highlight that code get rid of the variable is technically unnecessary and because the line of code is still pretty short I'm okay with just putting it all in one line but I could certainly use the variable like I did a moment ago so what have I done in my init function I have defined a initialization of the object that stores and self. houses the list of four houses and then in sort I'm accessing that same list but I'm randomly choosing the set of houses there now why have I done it in this way this to is General convention anytime you have a list of things that who knows maybe we'll change over time places like Harvard have constructed new houses over the years so you might have to change the list of available houses it didn't happen in seven books or eight films of Harry Potter but you could imagine maybe Hogwarts eventually has a fifth house so there's generally some value in putting list of constants toward the top of your file toward the top of the class so it's just obvious what the list of values is you don't want to necessarily tuck it away in some function like sort especially if you might want to use that function in sorry if especially if you want to use that list in multiple functions not just sort but if I kept adding to this class you might want to use that same list of houses in multiple functions so let's keep it in the object Itself by storing it in self. houses all right well we're about to change the course of history here perhaps let me do python of hat. and I think we're about to assign Harry to one of those four houses randomly huh name error name random is not defined well wait a minute where did did I go wrong here thinking back to our class on libraries why did my code break and not tell me where Harry is to be you do not import the random Library exactly if the random library or module is something I want to use I need to tell python that at the top of my file so let me go up here and do import uh random and then below that let me go ahead and clear my terminal window and try again python of haty crossing my fingers seeing where hair is going to end up and okay Harry as of now is officially in Hufflepuff despite what everything you've read or seen well let's run this again let me clear my window and run python of hatai and now he's in Ravenclaw that's consistent with using random let's clear that and run it again he's still in Ravenclaw but that could happen even though there's four choices let's do it again Hufflepuff back in Hufflepuff we can't seem to get the right answer so to speak now he's in Gryffindor albeit randomly so we seem to have a program that based on these Limited Test seems to indeed be assigning Harry to a house randomly now I'm somewhat lazily just letting sort print out this value I could do something else like return a string and then let me on line 13 do the printing for me but for now I think we have an example of a class called hat that nonetheless applies some of our lessons learned thus far today where I've created a class because a Sorting Hat is frankly well a I was about to say real world entity but really A Fant FY World entity and indeed that's a perhaps common puristic or mental model to have when should you use a class to represent something in your code very often when you're trying to represent some real world entity or fantasy world entity like a student which is something in the real world like a Sorting Hat which okay doesn't exist but hats certainly do so quite reasonable to have a class for hat and that's not always the case that classes represent real world entities but indeed we've seen thus far that int and stir and list and dict these are all structures that you might have in the real world we have integers and strings of text and other things so it rather makes sense to represent even those things more technically using a class as well you could use just a dictionary to represent a student or a hat but again with classes come all this and even more functionality but I honestly am not using classes in really the the right way here here why well in the World of Harry Potter there really is only to my knowledge one Sorting Hat and yet here I have gone and implemented a class called hat and again a class is like a blueprint a template a mold that allows you to create one or more objects thereof now most of my programs thus far have been pretty simple and I've just created one student but certainly if I spent more time in wrote more code you could imagine writing one program that has a list of students many more students than than just the one we keep demonstrating yet it would be a little weird it's a little inconsistent with the real or the Fantasy World of Harry Potter to instantiate one two three or more sorting hats there really is just one really one Singleton if you will which is a term of Art in a lot of contexts of programming so let me propose that we actually improve the design of the Sorting Hat so that we don't have to instantiate a Sorting Hat because right now this is kind of allowing me to do something like hat one equals hat hat two equals hat hat three equals and so forth I don't really need that capability I really just need to represent the Sorting Hat with a class but I don't really need to instantiate it why because it already exists I need just one so it turns out in Python that up until now we've been using as I keep calling them instance methods writing functions inside of classes that are automatically p a reference to self the current object but sometimes you just don't need that sometimes it suffices to just know what the classes and assume that there might not even be any objects of that class so in this sense you can use a class really as a container for data Andor functionality that is just somehow conceptually related things related to a sorting hats and there's this other decorator or function called class method that allows us to do just this so let me go back to my code here and let me propose that if I'm not going to instantiate multiple houses I don't really need this this in it method because that's really meant to initialize specific objects from that blueprint that template that mold so let me get rid of this but if I get rid of this I no longer have access to self but that's okay because it turns out in addition to their existing class methods there are also what we might call class variables and class variables exist within the class itself and there's just one copy of that variable for all of the objects thereof they all share if you will the same variable be it an INT or stir or in this case a list so what I've done here is Define inside of my hat class in a class variable called houses I don't say self because self is no longer relevant self refers to specific objects I want a variable inside of this class AKA a class variable that equals that list because it's inside of this hat now class I can use that list in any of my functions I've only got one now called sort but if I had more it would be accessible to all of those methods as well and with sort it also doesn't really make sense to sort within a specific sorting ha because again there I only want there to be one so I can actually specify that this is a class method by saying at class method and I don't pass in self anymore I actually by convention pass in the a reference to the class itself it's typically written as CLS y well if you wrote C ass that would actually conflict with the keyword class that we keep using up here so the world realized that oops we uh can't reuse that same phrase here so let's just call this class this is useful in some context including this one why well we notice what I can now do I can now change self to be just class why because house is now not an instance variable accessible via self. houses it is now a class variable accessible via class ouses or technically CLS do houses in this case but now the final flourish is this now I don't have to instantiate any hat objects as I used to on here line 13 I can just use functionality that comes with this class so I'm going to delete that line Al together I'm going to capitalize the Hat on this new line 13 and just say hat. sort quote unquote Harry so what have I done I've not bothered in intiating an object of type hat I am just accessing a class method inside of the Hat class that you know what is just going to work this is how class methods work you use the name of the class capital letter in all do method name passing in any arguments you want python is going to automatically pass in some variable via which you can refer to that class in that function that you've implemented inside of that class so that I can do something like this it's not that I want a variable called houses locally in this function I want the variable called houses that's associated with this current class so I can still access this same list that I defined on line six and now if I go back down here to my terminal and run python of haty enter Harry is still in Hufflepuff once more Harry is still in Hufflepuff once more Harry is back in Gryffindor at least randomly questions now on these class variables or these class methods which are in contrast with instance variables and instance methods and the one thing at least that's a little strange here is that even though there's a decorator called at class method there is not one called at instance method a method is just automatically a so-called instant method when you define it without any decorator can you have a class inside another class you can you can Define one class inside of another generally speaking this isn't done but there are cases where it can be helpful especially for larger more sophisticated programs so yes it is possible good other questions the question was about the self do houses when you when we remove it we uh and we pass data the variable is created itself why we remove the S so in the previous examples both of the Hat demonstration and also all of the student demonstrations we were uh create creating a student object by calling student capital S open parenthesis closed parenthesis with eventually name and a house passed in and then we were using the d uh the Double underscore init method to initialize the self. name and the self. house instance variables therein to those respective values in this latest version of the Sorting Hat I haven't bothered with self anywhere only because conceptually I don't need or want there to be multiple hats in the world I'm just using the class is kind of a container to bundle up this list of houses this sorting functionality maybe eventually I'll add more functionality to it but that's it and so sometimes you can use objectoriented programming in this somewhat different way when you want there to be functionality but it's not specific to any one specific hat it's specific to the Sorting Hat itself how about one other question now on these class variables or methods just another way of using objectoriented programming but to solve somewhat different problem well what's the difference between the class head and I know like a function of hat a good question so why are we using a class at all and not just having a file called hat. py with a variable called houses and a function called sort like why are we adding this complexity in this particular case we don't necessarily need to I could absolutely go in here I could get rid of the class I could uh undo this indentation I could could get rid of this decorator and I could get rid of hat Dot and I could just do this and additionally let's see let's get rid of class here let's get rid of class Here and Now run python of haty enter and it still works put Harry in the wrong house but that's what we have what happens randomly that's fine too what we're introducing today by way of object-oriented programming is just a different way of modeling the world it's not really compelling with an example like this frankly that's relatively simple it's not very complex there's not much functionality honestly the version that we just typed up these 10 lines this is fine this solves this problem but as our code gets longer as we start collaborating with other people as the problems we're trying to solve with code get more sophisticated you're going to find that your code gets messy quickly and you're going to find that you have a huge number of functions for instance in one file and some of them are related to each other but some of them are not well at that point wouldn't it be nice to just organize them a little differently and in the World of Harry Potter let's have a class for student let's have a class for Professor let's have a class for the Sorting Hat let's have a class for something else and so once your world gets much more complicated than some of the demonstrations we do here in class when we want to focus on individual ideas object-oriented programming is just a way of encapsulating related data that is variables related functionality that is methods inside of things that have names these things are called classes so it's just another way to solve problems and when we focused on libraries a couple of weeks back back that too was another solution to the same problem you could Define your own modules or packages put some of your data Endor functionality in there and that's fine too and sometimes which one you should use overlaps if you're familiar with vend diagrams the overlapping region might mean that you could use a class you could use a module or a package you could just use a single local file over time you'll develop an instinct and maybe even a personal preference for which tool to use all right let me propose now that we apply this same idea of a class method to clean up one other thing as well let me close hat dopy and reopen student. py as we left it earlier and let me go ahead and simplify it just a little bit uh I'm going to go ahead and get rid of the properties not because there's anything wrong with them but just because I want us to focus on some of the key ideas when we began with this program so I'm going to go ahead and keep main as well I'm not going to adversar try to change Harry's uh address there I'm going to instead go ahead though and just print the student but this is the thing I want to focus on here this in our previous student examples was kind of a missed opportunity to clean up my code well what do I mean by that well up here at the top of this file even though I've simplified it by getting rid of the properties and all of that error checking because I want to focus on the essence of this class now just the students's name and the house and the printing thereof this is by nature of classes and object-oriented programming theoretic Al all of my student specific functionality that is to say if I have functionality and data related to a student you the programmer my colleague would assume that it's all bundled up encapsulated so to speak inside of the student class and yet if you scroll down further what is this like there's a function called get student that just exists elsewhere in this file that prompts the user for a name prompts the user for a house creates the student object and then returns it like that's not wrong like it works and we saw many many times it kept working but this is a little weird right because what if this is a function that helps you get a student helps you get the name of a student and the house of a student why isn't that functionality in the class itself after all as my code gets more and more complicated and does more things I'm going to be looking at the student class for all student related functionality I'm not going to be scrolling down expecting that oh maybe there's some other student functionality just kind of randomly later in this file so it's not wrong but this is again evidence of maybe bad design not so much with this small program but this is an example again of code smell like something smells a little off here like this is probably going to get us in trouble by separating related functionality so again it's a design principle not a correctness concern but class methods allow us to address this too let me go ahead and do this I'm going to delete get student altogether leaving only main as my other function here and inside of my student class I'm going to do this I'm going to define a function even more simply called get and by nature of how class methods work it's going to take in the name of the class itself or reference there too as an argument and I'm going to move the functionality from get student into the student class and I'm going to do this name equals input quote unquote name uh house equals input quote unquote house and then what this function is going to do is return a new student object by calling class which again is just an automatically passed in reference to the class itself passing in name and house and I will admit this syntax seems a little strange that now I'm calling CLS and I'm passing in these arguments but let me do one final fix here let me go to the top of this function and more explicitly say this is a class method this solves a potential Chicken and the Egg problem so to speak whereby one needs to come before the other potentially so what am I doing here inside of my student class I now have a function called get it is I shall claim a class method what does that mean it just means I can call this method without instantiating a student object first there in lies the potential Chicken and the Egg problem and if unfamiliar that's an expression meaning well did the world have chickens first that laid eggs or was there an egg that then Bor uh yielded the chicken but how did the egg get there it's this sort of weird circular problem and that's what we're facing here it would be weird if you had to create a student object in order to call get in order to get another student object like that sounds messy let's just get a student via a class method that by definition does not require you to create a student object first just like the Hat in its final form we use the Hat class to just say hat Capital H do sort we didn't need to create a hat first we just used the class itself so what am I going to do here now let me go down to Main and instead of saying get student notice what I can now do student. get and everything else can stay the same all I've done now is I've migrated all of my logic from get student which was this own Standalone function but clearly related to students by name I've moved the same code really to inside of the student class in a more simply named function called get but I could still call it get student if I want it just seems a little redundant to call it get student in a student class so I'm simplifying so I have a method called get but I'm calling it a class method to avoid that chicken in the egg problem I want to be able to call get without having a student object in my universe already and the syntax for that is at class method the convention is to give this method at least one argument by by convention called CLS for class which is just going to be a reference to the class itself lines 11 and 12 are identical to what they've always been and get student the only new syntax here is this but this again is one of the features of object-oriented programming you can now instantiate a student object by just using CLS that's passed in I technically could use student capital S but it turns out I'm doing what's more conventional because this will both solve and avoid problems down the line with more complicated code this line here on line 13 just means create an object of the current class what class is that well whatever CLS is well that by definition of how it all works is going to be student and I want you to initialize it as always with name and house so now scrolling down my code is this and this is just nice to read you did perhaps have to acquire a taste for this and I sound a little odd saying this is nice to read but indeed student. just tells me what's going on I'm going to get a student I don't need a separate function written by me called get student in the file itself the get functionality is built into the class all my student related code now is together so let me go down to my terminal window and run python of student. enter let's type in Harry let's type in Gryffindor and we're back to where we began but but but everything related to students now is in this here class the only other thing in the file is Main and this conditional that we always use to avoid accidentally executing main when we're making a module or a package or the like so again a solution to a problem not a big one in the case of a relatively small program but one that you will eventually encounter as your programs get longer and longer with more and more entities to represent questions now on this use of a class method does the does the class have to be defined before the main function in terms of the order of the of the program really good question so when in doubt let's try this so let's try to change the order let's move main to the top which I've often encouraged so let's go ahead and above the class do this and notice now that technically line two is mentioning student which does not exist until line six and Below let me go ahead and clear my terminal and run python of studenty so far so good Harry Gryffindor okay uh indeed Harry's from Gryffindor the reason Michael it does not matter in this case is because we're not actually call main until the very end and just as in the past that means that python has a chance to read everything top to bottom left to right so everything exists I would say generally classes are defined at the top of the file however it would be even maybe cleaner to move the classes definition to its own file and then import it so essentially to make reusable code by putting it into your own module or package so that not just this program but many others can use that definition of student as well other questions now on classes class methods or the like I wanted to ask is there a way to um like declare all the all the possible all the possible attributes of the class because it looks so inconsistent um well so my takeaway there is this is Python's approach to these principles different languages like Java just take a different approach but have very similar features the syntax just tends to vary and this is how the python Community chose to implement this idea the right mental model ultimately is that these instance variables instant methods belong to or operate on specific objects a specific student a specific hat class variables and class methods operate on the entire class itself or in turn all objects of that class which we've not seen them a demonstration of but it's sort of a higher level concept so it turns out besides these class methods which are distinct from those instance methods which to be fair do not have their own decorator they just are by default instance method there's yet other types of methods you can have in classes in Python they tend to be called Static methods and they too come with another decorator called at static method which is a rabbit hole we won't go down but realize that there is yet other functionality that you can leverage within object-oriented programming but what we thought we'd do is focus really on some final core features that you see not just in Python but other languages as well and perhaps one of the most compelling features of objectoriented programming that we haven't yet used explicitly though it turns out we've seen implicitly over the past weeks is this notion of inheritance it turns out via object-oriented programming there's actually an opportunity to design your classes in a hierarchical fashion whereby you can have one class inherit from or borrow attributes that is methods or variables from another class if they all have those in common so what do I mean by this here well let me propose that we Implement uh over in vs code here a brand new file called wizard. let me go ahead and run code of wizard. py and then let's start as before defining a class called student and let's go ahead and first Define the underscore uncore init method which of course is minimally going to take an argument traditionally called self and in this case let's also have it take as before a name and a house and then in this init method let's go ahead and assign the instance variables self. name equals name and self. house equals house let's assume that there's some other functionality in this class as well dot dot dot but let's move on now to implementing the notion of a a professor in The Wizarding World as well so for this class let's call it professor and a professor let's say is also going to have its own initialization method so underscore underscore in it it's going to take self as always as the first argument uh a professor also has a name so we'll pass that in second two and even though some professors are heads of houses let's assume that a professor is really identified by their name and their subject area the class that they teach so we'll call this third argument subject now as before let's go ahead and assign self. name equals name and let's assign self. sub equals subject here and as before let's assume that there's some more functionality associated with professors as well well what do you notice already here in my definitions of St students and professors typically we're a bit reluctant to allow for any redundancy in our code and here I feel like my init method is taking a name for students my init method is also taking a name for a professor and I have these identical lines of code like self. name equals name and this is only going to get exacerbated if I now go and add some error checking so for instance How about if uh if not name we should probably be in the habit of raising something like a value error in an explanatory message like missing name and you know what if a professor is missing their name I should probably copy paste that code down here and that's where Red Flag should be going off whereby as soon as you start copy pasting code there's probably a better way so that we can write the code once and perhaps reuse it in some way and here too object-oriented programming offers a solution it turns out that object-oriented programming in Python also supports inheritance whereby you can Define multiple classes that somehow relate to one another they don't need to exist sort of in parallel in this way there could actually be some hierarchy between them so for instance in The Wizarding World we could argue that both a student and a professor are at the end of the day Wizards so maybe what we should really Define is a third class for instance called wizard that has any of the common attributes for students and professors alike and for now we've kept it relatively simple the only thing they have in common is a name and a name in student and Professor respectively so why don't we minimally factor that out first all right so let me go ahead here and just to keep things organized at the top of my file let's define a third class called Wizard and a wizard will have its own initialization method so decore uncore init underscore uncore and self as always and a wizard let's say for now is only going to be initialized with their name in this way and now I'm going to go ahead and do some of that error checking so if not name we'll raise a value error in the Wizard class otherwise we'll go ahead and do self. name equals name and heck dot dot dot maybe some other functionality as well but not a subject which is specific to professors and not a house which I've claimed is specific to students now I think we can begin to maybe remove some of the redundancies in our other classes here so for instance down with student why don't I go ahead and remove this error checking here and remove this error this assignment of self. name equals name because I'm already doing that in Wizard and similarly down here in Prof Professor why don't I do the same let's get rid of the error checking let's get rid of self. name equals name because I'm again I'm doing that already up there for Wizard as well but at the moment even though they're all in the same file I haven't told python that a student is a wizard and a professor is a wizard so I really need to link these two together and the way you can prescribe inheritance whereby one class should inherit from another or conversely one class should descend for another from another we can do this I can say class student but before the colon I can go in and say in parenthesis a student inherits from or is a subass of wizard which conversely is the super class of the student class so this just means that when I Define a student class go ahead and inherit all of the characteristics of a wizard as well and I'm going to do the same thing for Prof for Professor so parenthesis wizard after the class name professor and that's going to give me access to some of that same functionality but because my student class and my professor class still have their same init methods those are the methods that are going to get called whenever I create a student in code or I create a professor in code I need to somehow explicitly say that I also want to use the functionality in the Wizard classes init method and the way to do this in Python is is as follows let me go into my init method for student and let me call Super with no arguments which is a reference to the super class of this class so if this class is student the super class that is the parent class is Wizard so super open paren closed paren will have the effect of accessing the super class and then I'm going to go ahead and explicitly call its init method and I'm going to pass to the Wizards init method the name that the students init method was passed and I'm going to go ahead and do the same down here in Wizard this is one line of copy paste but I think I'm okay with it here because it's still allowing me to do all of the name assignment and the error checking up in the Wizard class instead I think we're okay now by just calling super. init for both student and Professor alike now admittedly this syntax is definitely out there the fact that we're calling super and parentheses and dots and underscore underscore on the left and the right of in it here but it's just a combination of these two ideas super open parenthesis closed parenthesis is a way of programmatically accessing a current classes parent class or super class and underscore uncore init of course is just referring to now that class's own initialization method now per the dot dot dots there could be a lot more going on in these classes but what's nice now is that wizard as a class is taking care of all of the assignment of a Wizard's name whether that wizard is a student or a professor and it's even doing some error cheing to make sure that the name was actually passed in meanwhile student is inheriting all of that functionality and using it by calling the super class's own init method but it's additionally taking the house that's presumably passed into the student Constructor function and assigning it to its own instance variable self. house and similarly Professor are we storing in self- thought subject the subject that was passed into there that one as well now how might we use these classes well we'll continue to wave our hands with a little bit of detail here but if at the bottom of this file or any other file that Imports this one I could now write code like this I could create a student variable and assign it the return value of the student Constructor call and maybe that student is named Harry and that student's house for instance might be Gryffindor and meanwhile I might do something like this professor equals professor over here and notice the lowercase s on the left capital S on the right same for Professor on the left lowercase and uppercase on the right respectively Professor quote unquote seus and how about defense against the dark arts will be his subject and meanwhile if we want more generically just a wizard who at the moment is neither student nor Professor teaching classes actively we could even do that we could do wizard equals wizard in capital W on the right hand side of the equal sign because it's the name of the class and someone like Albus passing in only albus's name not a house not a subject because in this case he's known only as a wizard meanwhile with each of these calls this line of code here will ensure that the init method for the wizard class is called this line of code here will ensure that the init method of the student class and in turn the init method of the super class wizard is called and then lastly on this final line of code will this syntax ensure that the init method of the professor class is called which in turn calls the init method of the super class as well any questions now on this idea of inheritance which is a key feature of a lot of objectoriented programming languages um so is there any situation where because uh from what I've seen so far A lot of times there's like a lot of nesting if you do subar does it go one up is there any situation where you know it's nested in another class as well um above wizard let's say a really good question if you were to have a super super class so your hierarchy is even taller than the two levels of uh hierarchy that we currently have absolutely but what's nice about object-oriented Pro what's nice about inheritance as the name implies is just as you might have inherited certain traits as a human from your grandfather and Grand mother or your great-grandfather or great-grandmother some of those properties can actually uh trickle down to you so to speak in the context of code as well so when you descend from another class that is when you subclass a a super class or a super super class you actually do inherit all of the functionality not just from one level above you but from two or three so you can indeed access some of that functionality as well and you can even override it if you want some of these classes to behave a little bit differently than others other questions on inheritance so it's kind of similar to the last one but can you have like two parents on the same level a really good question so there are ways to implement uh um descendants from multiple parents and there's different ways to do this not just in Python but other languages we've kept things simple here though by having a single uh inheritance path a good question how about one more question on inheritance can we have multiple arguments in super doubleit yes but in this case I'm only passing in name on line 18 and I'm only passing in name on line 10 why because on line two when I Define the init method for the wizard class I only expect a single argument but I could absolutely have under common functionality like I could add in a petronis if both students and professors have patronises that can come out of their wands I could have two arguments instead we've been using this feature of object-oriented programming now for quite some time in the form of exceptions indeed if you look at the official documentation for exceptions in Python you'll see that there's not even the ones we've seen in class like value error and others there's any number of others as well but they are all themselves hierarchical in nature this is just a subset of the available exceptions that come built into Python and you can actually as a programmer create your own exceptions as well but as this chart here uh captures hierarchically all exceptions we've seen thus far actually descend from or inherit from Super classes already so for instance at the bottom of this list here is value error which we've seen quite a bit and if you follow the line straight up on this asky rendition of this chart you'll see that value error has a parent class or super class called exception and the exception class meanwhile has a parent class called base exception why did the authors of python do this well it turns out that whether you have a uh value error or a key error or an assertion error or any number of others there's a lot of functionality common to all of those types of errors that you want uh all that you want a programmer to be able to use and so it turns out that the authors of python decided you know what let's not have a dozen or more different classes that all just have copy pasted similar functionality let's create this hierarchy so that even though the exceptions toward the bottom of this list are very precise they at least inherit that is borrow some very common fun fun ality up above so it turns out that when you use the try and the accept keyword in Python generally speaking we've tried to catch very specific exceptions like value error but technically you could capture the parent or even the grandparent exception for a given exception especially if you're not necessarily sure which one is going to get raised or better yet there could be many exceptions that get raised but you want to handle them all the same and you don't want to necessarily enumerate them in parenthesis separated by commas you want to say you want to handle all exceptions of a certain super class in much the same way so this has been latent this whole time anytime we've seen or used or caught or now raised exceptions and built into python is this hierarchy and if you were to invent your own exception generally you wouldn't want to start from scratch you would want to descend from that is subclass one of these existing exceptions and add your own twist on it your own functionality as well well there's one final feature of object-oriented programming that we'd like to share with you today in that it will perhaps be quite the eye opener is what you can really do now that you have classes at your disposal and this too surprise has been a feature you and I have been taking for granted for weeks now this has just worked but it's been implemented in a way that you can now leverage yourself it turns out that Python and some other languages too support this notion of operator overloading whereby you can take very common symbols like plus or minus or other such syntax on the on the keyboard and you can Implement your own interpretation thereof plus does not have to equal addition and minus does not have to equal subtraction and in fact you and I have already seen another context in which plus means something else plus has not always in Python meant addition per se what else has python used Plus for concatenation for concatenation for joining two strings for adding to a list can you use plus as well so plus has actually been funny enough overloaded by the authors of python for us and so we can use the same symbol in much the same way as addition but with different data types to solve slightly different problems well let me propose that we go back over to VSS code here and let me go ahead and create a new Final file called vault. py so code of vault. py and let me propose that we implement the idea of a vault at grots keeping on theme wherein there's a bank in the World of Harry Potter and within this Bank uh family and individuals have vaults containing all sorts of money in The Wizarding World and the type of money that exists in the World of Harry Potter are coins called gallions and sickles and canuts and those are in descending order of value and so inside of a vault might be a whole bunch of coins gold silver and bronze essentially each in those denominations tucked away so how can I go about implementing first of all the idea of a vault so that I can store for instance for Harry Potter how much uh coinage is in his family's Vault or for Juan resley the same let me go ahead in Vault up high and first create a class called Vault essentially meant to represent a bank vault perfect another real world or fantasy world entity that I want to represent with code I could use a tupple or a list or a dictionary but again I'm going to get a lot more functionality with classes and we'll see one final flourish with operators inside of this Vault class let's go ahead and do this let me Define my init method taking its first argument of self and let me Define uh three arguments to this when you create a vault in my code here I want to be able to initialize it with some number of gallions some number of sickles and some number of conuts I want the use the programmer to be able to pass in one or more of those values ideally but they can be optional so I'll give them defaults so let's go ahead and Define a parameter called gallions whose default value will be zero sickles whose default value will also be zero and canuts whose default value will be zero as well so the programmer can pass in one or two or three or heck even none of those and they'll all have some implied defaults how do I want to remember those values that are passed in well let me do this self. gallion equals gallion and self. sickles equals sickles and self. canuts equals canuts and so I could add some error checking especially if you don't pass in a number I could turn these into properties to do even more validation but let's keep it simple and as always Focus only on the new ideas so I'm just going to trust that these values were passed in and I'm going to immediately assign them to these instance variables what now do I want to do well let's come up with a way of printing out what is in someone's Vault ultimately but first let's do this let's create a a vault for The Potters by creating via assignment a new Vault and let's say that the Potters have 100 gallions 50 sickles and 24 canuts all right and that's in that Vault and let's print out for instance Potter all right let's run this code and see how it works now let me go ahead and run python a vault. pi enter okay seems to work no syntax errors or anything else but this is not very enlightening how do I fix this thinking back to what we've done before you have to use the underscore underscore s exactly I need to use one of those special methods that comes with classes and Define for myself how I want a vault to be printed as a string so let me go ahead and do that let me Define the stir method taking in self as its sole argument here and let's just return a very simple string that just reveals what's in the vault so I'm going to return a formatted F string uh inside of which is self. gallan and then the word uh gallion so I know which those are uh then let's do self. sickles and let's output the word sickles and then lastly let's output self. canuts and then canuts here so I know in this string just how many of each of those uh coins I have in this particular family's Vault all right let me go ahead and run python of vault. changing nothing else except the stir method and now we see indeed that Harry has 100 gallions 50 sickles and 25 canuts all right well let's do one thing more here below that let's go ahead and Define a Weasley variable and Ron never seemed to have quite as much uh money in the vault as did Harry so let's say that the Weasley Vault will have 25 50 and 100 so I'll just reverse the order of those denominations uh rather than Harry's 100 5025 and now let me go ahead and print Weasley like this and let's go ahead and clear my terminal window run python of vault. this time that stir method will be invoked twice once for each of those Vault objects and we'll see indeed that the first one for Harry's got 50 and 25 respectively versus Ron's 25 50 and 100 respectively but now let's do something interesting suppose that you wanted to combine the contents of two vaults be it Harry's and Ron's or any other two people how would you go about doing this in code well if I wanted to combine the vaults for someone I could do this well I could do gallion equals let's do potter. gallion uh plus Weasley do gallion that gives me a variable called gallion that has the sum of Harry and Ron's gallion let's next do sickles equals potter. sickles plus Weasley do sickles and then lastly let's do canuts equals potter. canuts plus Weasley do canuts I've got three variables what can I now do with these values well let's create a third a new Vault uh total will be the name of this variable equals a new Vault capital V notice and now let's pass in those three new variables gallions sickles and canuts and that's it and let's print out this total Vault so we should now see three vaults one for Harry for Ron and the combination the addition of the two let me go ahead and rerun python of vaulty and there we have it uh what was 10050 25 and 25 50 and 100 combined through addition now is 125 100 125 so pretty straightforward using techniques from weeks ago where we're just declaring a few new variables and doing some addition but wouldn't it be cool if I could do something like this wouldn't it be cool if I could just somehow not manually create my own Vault and do all of this annoying math up here what if I could just do Potter plus Weasley and get rid of all of this logic here like wouldn't it be nice if I overload the operator no we know as plus just like stir does just like list does to allow me to add two vaults together on the left and the right well it turns out in Python and through operator overla there is a way to do just this if you consult the documentation there are there's this and so many other special methods that come with classes the third one we see here is this one here underscore uncore add underscore underscore and you see that it very generically is described in the documentation as working for any object be it a vault or a stir or a list or something else by convention it's going to take a first argument called self and then it's going to take some other argument by convention called Other Self in effect is going to be referring to whatever object is on the left of a plus sign other is going to be referring to whatever is on the right hand side of a plus sign thereby giving us a way of describing in code the operand on the left and the operand on the right of the operator Plus in between that is to say if I go back to vs code here what I'm trying to do is Implement support for this well let me try without writing any other code just yet python a vault up high enter type error unsupported operand types for Vault and Vault that is to say python at this moment does not know what it means to add two vaults together right you and I might have an instinct probably want to combine the gallions and the sickles and the canuts respectively python doesn't know that it just knows that you have a new class called Vault but let's teach python to do this let me clear my terminal window let me scroll back up to the class itself where at the moment I only have two special methods in it and stir but let's add this third all right let me go into the class here and Define underscore uncore addcore underscore and then specify its first parameter as self as before and then a second parameter for this particular method called by convention other now as always I could name those parameters anything I want but I'm going to stick with convention Here and Now inside of this method am I going to have to now add together the contents of two vaults well what two vaults well if we scroll down to our goal at hand the goal of course is to add this Vault plus this other Vault Potter plus Weasley respectively well it turns out in Python that when you do overload an operator like Plus what's going to happen automatically as soon as python sees that is it's going to call that underscore underscore ad underscore underscore method and it's going to pass into it to our arguments whatever the operand is on the left Potter in this case and whatever the operand is on the right Weasley in this case and those values are going to get passed in as self and other respectively what that means is that we can access their contents up here in our implementation of AD as follows let me go ahead and Define a local variable called gallion and set that equal to for instance the sum of self. gallions whatever's in uh Potter's vault in this case plus whatever is in Weasley's vault in this case which would be other do gallion let me do the same for sickles self. sickles plus other do sickles and let me lastly do that for canuts so self. canuts plus other. canuts but at the end of the day I'm going to need to return a brand new bigger Vault that contains all of those contents together and if we ultimately want to assign that bigger Vault to a variable like total here on the left we better indeed return a value from this ad method so I'm going to go ahead and give myself a brand new vault as by returning Capital vault which of course is going to call My Vault function into which I can now pass some of those initialization arguments well how many gallion sickles and canuts do I want this brand new Vault to contain well I want it to contain this many gallions this many sickles and this many canuts so ultimately what we're doing in this implementation of ad is adding together those gallion sickles and canuts passing them to the Vault function so that we get a brand new bigger Vault and return that all together so now I've defined this new special method called add that should now just make Plus work for two vaults all right let's see let me run down to my terminal window python a vault up high and hit enter and voila now we've implemented an overloaded operator plus to do what you and I as humans would hope would be the case when you add two vaults together but I've now written the code more specifically to teach python what it means concretely to add two vaults together and it's with very similar code in effect underneath the hood that python is doing this for two strings to concatenate them together to joining to lists into a new list with lists and so many other classes as well any questions now on operator overloading or this example here how would you go about creating a function for adding a student and a vault for two two separate classes how would that be possible let me see what happens here I don't know off hand let's do this let's create a stir and see what happens if I add Potter plus a stir stir object yeah okay so it would work I'm just figuring this out as I go here Eric so just to re be clear what I did was I just changed Weasley to stir just to see what would happen when I add a vault plus a stir and it will work theoretically why because so long as the type of value on the left has an add method implemented other can be any type that you want you just have to decide and code what it's going to mean conceptually to add a vault plus a string which in this case probably doesn't make any sense at all but it's possible it's going to be the operand on the left and I'm inferring that I did not know the answer a moment ago I'm inferring that because what I got was an attribute error here on line 11 because python did not like this other gallion didn't work but I could make it work by figuring something out really good question didn't know that one myself other questions on operator overloading can you define new operators in Python I don't think so there is a very long but precise list of operators that you can overload I do not believe you can assign arbitrary characters to be operators in Python uh let me defer to Carter in the chat to revoke okay I'm seeing two of my colleagues are saying no not possible so I'm going to go with my first instinct no otherwise that'd be kind of cool you could make Emoji do whatever you want to how about one final question on operator overloading is that the only operation you can do uh is a far as like can you do a subtraction as well you can you can do so many others let me um if Carter you don't mind pulling up this URL here so this link here special method names in today's slides you'll see a long list of all of The Operators that you can overload you can do less than equals than plus equals minus equals pretty much any symbol you've seen me type on the screen can be overloaded in the context of classes so even though today we focused entirely on object-oriented programming this is a technique that we've been using really since the first week of the class because indeed those ins those stirs those floats those lists those dictionaries and so much more were already underneath the hood this whole time classes and objects thereof but you now as a programmer have the ability to create your own classes with your own instance or class variables with your own instance or class methods with your own properties and even with your own custom behavior for operators so ultimately you can absolutely continue using those simple tles or lists or those dictionaries or other structures as well but object-oriented programming and with it classes and now these objects is just another tool in your toolkit and dare say as your code gets more sophisticated and your problems get bigger you'll find that being able to model these real world or even fantasy world entities with classes and related data and functionality will ultimately just allow you to Define code that's not just correct but ever well designed as well this was cs50 [Music] [Music] all right this is cs50's Introduction to programming with python my name is David me and over these past many weeks have we focused on functions and variables early on then conditionals and loops and exceptions a bit of libraries unit tests file AO regular Expressions object-oriented programming and really Etc and indeed that's where we focus today is on all the more that you can do with python and programming more generally Beyond some of those fundamental concepts as well in fact if you start to flip through the documentation for python in all of its form all of which is as always accessible at docs. python.org you'll see additional documentation on Python's own tutorial in library uh its reference it's how to and among all of those various documents as well as others more online you'll see that there's some tidbits that we didn't quite touch on and indeed even though we themed these past several weeks of around fairly broad topics that are rather essential for doing typical types of problems in Python it turns there's quite a number of other features as well that we didn't necessarily touch on that didn't necessarily fit within any of those overarching Concepts or might have been a little too much too soon if we did them too early on in the course and so in today our final lecture will be Focus really on all the more that you can do with python and hopefully wet your appetite for teaching yourself all the more too for instance among Python's various data types there's this other one that we haven't had occasion to yet use namely a set in mathematics a set is typically a collection of values wherein there are no duplicates so it's not quite a list it's a bit more special than that in that somehow any duplicates are eliminated for you well it turns out within python this is an actual data type that you yourself can use in your code and via the documentation here might you be able to glean that it's a useful problem if you want to somehow automatically filter out duplicates so let me go ahead and go over to VSS code here and let me go ahead and show you a file that I created a bit of in advance whereby we have a file here called houses. and in houses. I already went ahead and whipped up a big uh list of students inside of which is a number of dictionaries Each of which represents a student's name and house respectively now this is a pretty sizable dictionary and so it lends itself to iteration over the same and suppose that the goal here was quite simply to figure out well what are the unique houses at Hogwarts in the World of Harry Potter it would be nice perhaps to not have to know these kinds of details or look them up online here we have a set of stud students albeit not exhaustive with all of the houses but among these students here what are the unique houses in which they live well I could certainly as a human just eyeball this and tell you that it's well Gryffindor Slither and Ravenclaw but how could we go about doing it programmatically for these students as well well let's take one approach first here let me go into houses. and let me propose that we first how about create an empty list called houses in which I'm going to accumulate each of the houses uniquely so every time I iterate through this uh list of dictionaries I'm only going to add a house to this list if I haven't seen it before so how do I express that well let me iterate over all of the students with for student in students as we've done in the past and let me ask a question now so if the current student's house and notice that I'm indexing into the current student because I know they are a dictionary or dict object and if that student's house is not in my houses list then indented am I going to say houses. append because again houses is a list and I'm going to append that particular house to the list then at the very bottom here let me go ahead and do something somewhat interesting here and say for each of the houses that I've accumulated in I could just say houses but if I just say houses what was the point of accumulating them all all at once I could just do this whole thing in a loop let's at least go about and sort those houses with sorted which is going to sort the strings Al alphabetically and let's go ahead there in and print each of the houses let me go ahead now in my terminal window and run python of houses. and hit enter and there we have it Gryffindor Ravenclaw Slytherin in alphabetical order even though in the list of dictionaries up here technically the order in which we saw these with was Gryffindor Gryffindor Gryffindor slitherin Ravenclaw so indeed my code seems to have sorted them properly so this is perfectly fine and it's one way of solving this problem but it turns out we could would use more that's built into the language python to solve this problem ourself here I'm rather Reinventing a wheel really the notion of a set wherein duplicates are eliminated for me so let me go ahead and clear my terminal window and perhaps change the type of object I'm using here instead of a list which could also be written like this to create an empty list let me go ahead and create an empty set whereby I call a function called set that's going to return to me some object in Python that represents this notion of a set wherein duplicates are automatic eliminated and now I can tighten up my code because I don't have to use this if condition myself I think I can just do something like this inside of my Loop let me do houses. add so it's not a pend for a set it's a pen for a list but it's add to a set per the documentation then let me go ahead and add this current student's house and now I think the rest of my code can be the same I'm just now trusting per the documentation for set in Python that it's going to filter out duplicates for me and I can just blind add add add add all of these houses to the set and any duplicates already there will be gone python of houses. and enter and voila we're back in business with just those three there as well let me pause here to see if there's any questions now on this use of set which is just another data type that's available to you another class in the world of python that you can reach for when solving some problem like this how can we locate an item in a set for example find Griffin door in the oh how do you find an item in a set you can use very similar syntax as we've done for a list before you can use syntax like if Gryffindor in houses then and you can answer a question along those lines so you can use in and not in and similar functions as well other questions on set okay what happens if you have a similar house name let's say instead of slithering it is maybe an O instead of an I will the fall Loop look throughout each of those um letters in the house name uh it would compare the string so if Slytherin appears more than once but is slightly misspelled or misc capitalized if I heard you right those would appear to be distinct string so you would get both versions of Slytherin in the result however we've seen in the past how we can clean up users data if indeed it might be messy we could force everything to uppercase or everything to lowercase or we could use capitalize the function built into stirs or title case that would handle some of the cleanup for us in this case because the data is not coming from humans using the input function I wrote the code in advance it's safer to assume that I got the houses right but that's absolutely a risk if it's coming from users allow me to turn our attention back to some of the other features here that we can leverage in Python if we dig further into the documentation and read up more on its features well in some language there's this notion of global variables whereby you can define a variable that's either local to a function as we've seen many times or if you put a variable outside of all of your functions perhaps near the top of your file that would generally be considered a global variable or in the world of python it might be specific to the module but for all intents and purposes it's going to behave for a given program as though it is global however it turns out that if you do this when solving some problem down the line whereby you have multiple functions and you do have one or more variables that are outside of those functions you might not be able to change those variables as easily as you might think so indeed let me go back to vs code here and in just a moment I'm going to go ahead and create a new file how about called bank.pay let's go ahead and implement the notion of a bank wherein we can store things like uh money in various forms and let me go ahead and do this let me go ahead and Implement a very simple bank that simply keeps track of my total balance the number of dollars or cents or whatever I might be storing in this bank and I'm going to give myself a very iable called balance at the top which is an integer a set to zero now let me go ahead and Define a main function as we often do and inside of my main function let me go ahead and print out quote unquote balance and then print out the value of balance itself passing to print as we've often done more than one argument so that they get uh separated by a single white space And now since I have a main function really setting the stage for doing more interesting things soon let me go ahead and do our usual if the name of this file equals equals underscore uncore main then go ahead and call Main so this is a terribly short program but it's perhaps representative of how you might solve some future problem in Python whereby you have a main function that's going to eventually do some interesting stuff and at the top of your file you have one or more variables that are just useful to keep there because then you know where they are and perhaps not just main but other functions can access them as well so let's see when I run this program python of bank.pay I would hope based on my own in thus far then I'm going to see that my current balance is zero that is to say even though the balance variable is defined on line one hopefully I can still print it on line five inside of main even though balance was not defined in my main function here we go hitting enter and voila balance zero so it does seem to work even if you declare a variable in Python outside of your functions it appears that you can access it you can read the value of that variable even inside of a function like Maine well let's get a little more adventurous now because this program really isn't solving anyone's problems let's go ahead and Implement more of a bank like the ability to deposit money into the bank and to withdraw money from the bank thereby giving me some more functions that might very well need to access that same variable Let Me Clear My terminal window here and let me go ahead and pretend for the moment that I have the ability to deposit say $100 or 100 coins whatever the unit of currency is here and then maybe I want to withdraw straight away 50 of those same dollars or coins and now let me go ahead and just print out at the bottom of main what my new balance should be so that in an Ideal World once I've deposited 100 then withdrawn 50 after starting at zero I'd like to think that my new balance on line 8 should indeed be 50 all right but I haven't implemented these functions yet so let's do that as we've done in the past down here I'm going to go ahead and Define another function deposit I'm going to say that it takes an argument called n for number of coins or dollars or the like and I'm just going to do this I'm going to go ahead and say balance plus equals n thereby changing the value of N I could do it more verbosely balance equals balance plus n but I'm going to use the shorter hand notation here instead and now let's Implement withdraw so Define a function called withdraw it to is going to take a variable uh an argument n for number of dollars or coins and now I'm going to go ahead and subtract from balance using minus equals uh n as well and I'm still going to call Main if the name of this file is main so what have I done I've just added not just one but three functions total all of which apparently need to access balance by uh printing it incrementing it or decrementing it as we've seen here all right let me go ahead and focus on these three functions here let me go back to my terminal window and run python of bank.pay and hit enter and wow seems like we've introduced some number of problems here and what are these problems well Unbound local error is perhaps the first time we've seen this one here local variable balance rep referenced before assignment and that's a bit misleading definitely confusing right because I absolutely assigned balance of value on the top of my code and indeed if I scroll back up nothing has changed or been lost up there it's definitely been assigned a value and now on line uh 12 it would seem that when deposit is called I'm just trying to access that variable again so intuitively what might explain this error message Unbound local error what is python telling us there that python can or can't do when it comes to these so-called Global variables that are at the top of my file uh so if you want to change this V variable you should uh write in inside the function Main and the global variable unchangeable yeah so if you want to change the value it might need to be local to the function if you are trying to change a global variable though in a function it clearly does not work so it's okay to read a global variable read meaning access it and print it and so forth but apparently you can't write to a global variable in the same way from within one of these functions all right well maybe the fix is to do this let me clear my terminal window in that error and maybe I could just do this let's get rid of the global variable and let's go ahead and put it for instance inside of main might this now work well let me try this now python of bank.pay enter that alone did not solve it I still have an Unbound local error this time though it's for a different reason it turns out now that balance on line two is by definition a local variable a local variable is one that exists in the context of a function at least in this case a global variable is the opposite one that does not for instance at the top of my file so here is another distinction in Python if you declare a variable in a function like main just as I've done on line two with balance it is indeed local to that function deposit and withdraw do not have access to that same variable why because it's local to Main and so you would think now we're kind of stuck in this vicious cycle well maybe the solution then is to move uh balance globally so all three functions can access it but clearly where we began as oena noted we can't therefore change it so what turns out the solution to this problem in Python is ironically exactly this keyword here it's a little different as you might have seen if you programed before in other languages but there's indeed a keyword in Python called Global that allows you to tell a function that hey this is not a variable that's local to you I mean it to be a global variable that I want you to edit so if I go back to VSS code here clearing my terminal window to get rid of that error let me go ahead and undo the change I just made and put balance back at the top of my file but this time time what I'm going to do is I'm going to inform my two functions that need to change the value of balance that it is indeed Global by typing Global balance again here as well as here Global balance I still leave the same lines of code now on lines 13 and 18 that increment and decrement balance but this now use of keyword Global is a little bit of a clue to python that oh okay it's not a local variable this is not a bug that you've introduced you mean for to edit this variable up above so now let me go ahead in my terminal window and run python of bank.pay I'm hoping to see that my balance is 0 + 100 minus 50 is 50 and indeed it now is it starts off at zero per my first print statement on line five but it ends up at 50 total at below that on line eight let me pause here to see if now there's any questions on these Global or local variables what happens when you declare a variable globally and as in the same variable globally and in a function a good question you're always thinking about the so-called Corner cases so if you declare a variable both globally like at the top of your file and then an identically named variable inside of a function same name the ladder Will Shadow so to speak the former that is you'll be able to use the ladder that is the local variable but it will have no effect on the global variable temporarily python will only know that the local variable exists so in general the rule of thumb is just don't do that not only might it create bugs in your code because you don't quite change what you intend to change it's also perhaps uh nonobvious to other readers as well other questions on globals or locals okay what if we decide to add balance as an argument inside the main function yeah another good Instinct but in this case that also is not going to solve the problem because if you pass in a variable like balance to each of the function functions and then change it within that function it's only going to be changing in effect a local copy thereof it's not going to be changing what's outside of those functions so I think we actually need a better way altogether and in fact allow me to transition to perhaps a modification of this same program recall that we looked most recently at this notion of objectoriented programming whereby you can model real world entities for instance a bank and you can model and encapsulate information about that real world entity for instance like someone's account balance so let me propose that we actually do this let me start from scratch with bank.pay get rid of the global variable Al together and actually use some objectoriented code let me define a class called account to represent someone's bank account and then let me go ahead and initialize with my init method which again takes by convention at least one argument called self let me go ahead and initialize every person's bank account to some value like zero now how can I do that well I'm going to go ahead and do self. balance equals 0 thereby giving me an instance variable called balance initialized for this account to zero but I'm going to proactively remember how we also introduced this notion of properties which might otherwise collide with the names of my instance variables so just by convention I'm going to do this I'm going to rename this instance variable proactively to underscore balance to effectively indicate that it's private even though that's not enforced by python it's just a visual clue to myself that this is something that really I should not or other code should not touch just functions in this class now let me go ahead and do this let me go ahead and Define an actual function called balance that really is going to be a property whose purpose in life is just to return self. balance and I'm going to go explicitly and say this is indeed a property of this class now let me go ahead and reimplement those other two functions deposit and withdraw but in the confines of this class so I'm going to say Define uh deposit it's going to take in an argument self as always but an additional One n a number of dollars or coins to deposit and how do I now manipulate this well I'm going to do self doore balance plus equals n and now down here I'm going to do def withdraw self n just like for deposit but here I'm going to do self. balance minus equals n and now if I go down below this class I'm going to go ahead and and Define myself a main function just so I can try this now out I'm going to go ahead and create an account object by calling the account Constructor that is the name of the class with two parentheses if I'm not passing in any arguments to in it I'm going to go ahead now and print out as before the balance of my account but to do that I'm going to access the property of that account like this and I'm going to go ahead now and say deposit another $100 or coins with deposit 100 and I'm going to go ahead like before and also now immediately withdraw for whatever reason 50 of the same and now I'm going to print One Last Time balance followed by account. balance again accessing that property and for this whole thing to work of course I need one of these if name equals equals uncore main then go ahead and call Main now before I run this you'll see that it rather escalated quickly I had a very simple goal at hand to implement the notion of a bank and I was able to implement that perfectly fine ultimately by declaring balance to be Global but then to tell each of my functions that it is indeed Global but that's not really the best form of encapsulation we have at our disposal now right per our focus on object-oriented programming if we're trying to implement some real world entity like an account at a bank that's what classes allow us to do and it allows us to solve that same problem perhaps a little more cleanly certainly if we're going to accumulate more and more functions or methods over time so if I didn't make any mistakes here if I run python of bank.pay and hit enter now you'll see that it just works just fine because in the world of classes in Python these so-called instance variables are by definition accessible to all of the methods in that class because we're accessing them all by way of that special parameter self so which way to do it for a reasonably small script wherein you are simply trying to implement uh a script that has some Global uh information like an account balance that you then need to manipulate elsewhere the the global keyword is a solution to that problem but generally speaking in many languages python to some extent among them using Global variables tends to be frowned upon only because things can get messy quickly and it be can become less obvious quickly exactly where your information is stored if some of it's up here some of it's in your function so generally the rule of thumb is to use Global variables sparingly though technically speaking in Python these Global variables are technically local to our module if we were indeed implementing a library and not just a program so in short try to use Global variables sparingly but when you do there is a solution to these same problems questions now on globals or our reimplementation of the same idea but using full-fledged objectoriented programming uh I just uh would like to ask uh what this property does what this property does so if I go back to VSS code here you'll see that this was a Technique we looked at in our lecture on object-oriented programming whereby a property is a instance variable that's somehow protected it allows me to control how it can be read and written so in this case I only have what's called generally a Setter and sorry in this case I only have what's generally called a getter and there's no mention of the word getter here this is just what app property means that function balance will allow me recall to use syntax like this where I can pretend as though balance is indeed with no underscore an instance variable but I can now prevent code like mine in main from trying to change balance because I do not have a Setter I would not be able to do something like account balance equals a th000 to just give myself $1,000 doll or coins because I have not defined a Setter so again per our focus on object-oriented programming these properties just allow me some finer grain control some languages allow you to Define variables that are so to speak constant that is once you have set a value to them you cannot not change the value of that variable and that tends to be a good thing because it allows you to program defensively just in case you accidentally or someone else accidentally tries to modify the value of that variable if you have declared it in some language as a constant it cannot be changed or usually cannot be changed without great effort unfortunately in Python we're again on the sort of honor System here where we have conventions to indicate that something should be treated as though it's constant but that's not actually enforced by the language so for instance let me let me go back here to vs code and let me create a new file for instance called meow. pie and let's see if we can't implement the notion of a cat meowing on the screen so I'll do code of meow. py and in meow. pie let me go ahead for instance and Implement a very simple program that just has a cap meowing three times so how about this for I in the range of three go ahead and print out quote unquote meow all right well we've seen in the past how we can clean this up a little bit for instance if I'm not actually using I I might as well pythonic just change the name of that variable to underscore even though that has no functional effect here but here we have this three sort of randomly hardcoded that is typed explicitly into my code and it's totally not a big deal when your code is only two lines but imagine that this is a much bigger program with dozens or even hundreds of lines and imagine that one of those lines just is a three in there somewhere like you're never going to find that three very easily and it's going to be very easily overlooked by you or colleagues or others that you've hardcoded some magic value like a three right there in your code so it tends to be best practice not just in Python but other languages as well anytime you have what is essentially a constant like a number three that shouldn't ever change is to at least let it Bubble Up surface it to the top of your code so that it's just obvious what your code's constant values are and so by that I mean this at the top of this file it would probably be a little clear to colleagues and frankly me tomorrow after I've forgotten what I did today to Define a variable like meow and set it equal to three and then instead of hardcoding three here or even lower in a much bigger program let me just go ahead and pass in that variable's value to my Loop so that now it's just kind of obvious to me that meow is apparently the number of times to meow and if I ever want to change it the only code I have to change is at the very top of my file I don't need to go fishing around or figure out what's going to break what do I need to change I just know that I can change these constants up at the top the problem though with Pip Pyon is that python doesn't actually make variables constant it's indeed a convention in Python and some other languages to at least capitalize your variables when you want to indicate to the world that you should not touch this it is constant but there is literally nothing in my code preventing me from saying you know what today I feel like four meows instead like that would work in other languages though there's typically a keyword or some other mechanism syntactically that would allow you to prevent line three current Cy from executing so that when you tried to run your code you would actually get an error message explicitly saying you cannot do that so python again is a bit more on the honor System when it comes to these conventions instead now it turns out there's other types of constants quote unquote that python uh typically manifest and in fact let me go ahead and change this around a little bit let me delete this version of meow and let me introduce again a class from our discussion of object-oriented programming like a class representing a cat another real world entity recall that within classes you can have not just instance variables but class variables that is variables inside of the class that aren't inside of self per se but they're accessible to all of the methods inside of that class here too there's a convention but not enforced by python of having class constants whereby inside of the class you might want to have a variable that should should should not be changed but you just want to indicate that visually by capitalizing its name so for instance if the def number of meows for a cat is meant to be three I can literally inside of my class but outside of any of my defined methods just create a class variable all capitalized with that same value and then if I want to create a method like uh meow for instance which as an instance method might take in self as we know and then I might have my Loop here for underscore in the range of and now I need to access this the convention would be to say cat. meow to make clear that I want the meow variable that's associated with the class called cat then I'm going to go ahead and print out one of these meows and now at the bottom of my code outside of the class let me go ahead and do something like this let me instantiate a cat using the cat Constructor notice this is important per our discussion of oop the class is capitalized by convention but the variable over here is is lowercase and I could call it just C or anything else but I kind of like the symmetry of calling it little cat here and big cat so to speak over here and now if I want this particular cat to meow that default number of three times I can just do cat. meow like this and that method meow is going to per line five access that class constant but again it's constant only in the fact only in the sense that you should not touch that not that it's actually going to be enforced by the language all right let me go ahead then and run this with python of meow STP and there it is three of our meows meow meow it turns out that python is uh dynamically typed language that is to say it's not strongly typed whereby when you want an INT you have to tell the program that you are using an INT you don't have to tell the program that you are using a stir or a float or a set or anything else generally speaking to date you and I when we're creating variables we just give a variable a name we frequently assign it using an the equal sign some other value and honestly python just kind of dynamically figures out what type of variable it is if it's uh quote unquote hello world the variable is going to be a stir if it's 50 the integer the variable is going to be an INT now in other languages including C and C++ and Java and others it's sometimes necessary for the programmer to specify what types of variables you want something to be the upside of that is that it helps you detect bugs more readily because if you intend for a variable to store a string or an integer but you accidentally store an integer or a string the opposite or something else Al together your uh language can detect that kind of mistake for you when you go for instance to run the program it can say no you've made a mistake and you can fix that before your actual users detect as much in Python 2 here it's again more of a friendly environment where you can provide hints to python itself as to what type a variable should be but the language itself does not strongly enforce these rather you can use a tool that will tell you whether or not you're using a variable directly but it's typically a tool you would run as the programmer before you actually release your code to the world or if you have some kind of automated process you can run this kind of tool just like you could reformat or lint your code with some other program before you actually release it to the world so how might we go about using these so-called type penss well they're documented in the usual place in Python's own documentation and it turns out there's a program that's pretty popular for checking whether or not your code is adhering to your own typ pins and that program here is called mypie and it's just one of several but this one's particularly popular and can be easily installed in the usual way with Pip install mypie and its own documentation is at this URL here but we'll use it quite simply to check whether or not our variables are indeed using the right types so how can we go about doing this all right let me go back here to vs code clear my terminal window and in fact erase meow. Pie as it currently was and let's Implement a different version of meow that quite simply has a function called meow that does the actual meowing on the screen and then I'm just going to go ahead and call that function down toward the bottom I'm not going to bother with a main function just for Simplicity so that we can focus as always only on what's new so here we are defining a function called meow it's going to take a number of times T meow for instance n for number and inside of this function I'm going to do my usual for underscore in the range of n Go ahead and print quote unquote meow So based on our earlier code I think this is correct not bothered defining the variable as I I'm instead using the underscore because I'm not using it anywhere but I think I now have a working function whose purpose in life is to meow zero or one or two or three or more times well let's use this function again not bothering with main I'm just going to keep my function at the very top because there's only one and I'm going to write my code uh here on line six so I'm going to give myself I'm going to ask the user for a number and I'm going to go ahead and prompt them in the usual way for that number of times to meow and now I'm going to go ahead and call meow on that number now some of you might see what I've already done wrong but perhaps I myself don't so let me go into my terminal window and run python of meow. py the goal being to prompt me this seems to be working I'm going to type in three and I would expect now the meow function to print out meow three times enter but no there's some kind of type error here stir object cannot be interpreted as an integer why might that be why might that be because the input function returns a string instead of an in exactly the input function returns a string or a stir not an INT so in the past of course our solution to this problem has just been to convert the string to an INT by using the int function but now let me start programming more defensively so that honestly I don't even find myself in this situation at all let me go ahead and do this let me add what's called a type hint to my function that explicitly specifies for meow what type of variable should be passed in I'm going to go ahead now and change the very first line of my code and my function to specify that n colon should be an INT and this is a type hint the fact that I've added a Col in a space and the word int is not creating another int or anything like that it's just a hint an annotation so to speak to python that this variable on the left called n should be an INT now unfortunately python itself doesn't care because again these type hints are not enforced by the language and that's by Design the language itself in the community prefers that python be dynamically typed not so strongly typed as to require these things to be true but if I run meow. py type in three again the same error is there but let me go about trying this mypie program an example of a program that understands typ hints and if I run it proac actively myself can find bugs like this in my code before I or worse a user actually runs and encounters something cryptic like this type error here let me clear my terminal window and this time run my Pi space meow. so I'm going to run my piie on my program but I'm not running python itself when I hit enter we'll see this all right we see now that my pie found apparently an error on line seven error argument one to meow has incompatible typ stir expected int so it's still an error message but mypie is not a program that my users would use this is a program that you and I as programmers would use and because we have run this code now before we for instance released this program to the world I can now see even before the code is called or run oh I seem to be M using my argument to meow wrong I had better fix this somehow well I can actually go about in uh hint adding typ hints even into my own variables here so as to catch this another way too if I know on line six that I'm creating already a variable called number and I know already that I'm assigning it equal to the return value of input I could give my pi and tools like it another hint and say you know what this variable called number should also be an INT that is to say if I now start getting into the habit of annotating all of my variables and arguments to functions maybe my Pi can actually help me find things quite quickly as well before I get to the point of running python itself let's go ahead and try this again my piie of meow. Pi and hit enter and this time notice that my Pi actually found the mistake a little more quickly notice this time it found on line six that error incompatible types and assignment expression has Type stir variable has Type int so before I even got to the point of calling meow line six via this typeint when used and analyzed by mypie has helped me find oh wait a minute I shouldn't be assigning the return value of input to my variable called number in the first place why mypie has just pointed out to me that one returns a stir I'm expecting an INT let me fix this now instead all right so let me clear my terminal window and now let me do what most of you were probably thinking I should have done in the first place after all of these weeks but now let me go ahead and convert the return value of input to an integer for today's purposes I'm not going to try to catch any exceptions or the we're just going to assume that the user types this in properly and now let me go ahead and run my piie of meow. pie having not only added two typeint to my argument to my function to my variable down here on line six and I've also now fixed the problem itself let me go ahead and run my piie and success no issues found in one source file now it's more reasonable for me to go and run something like python of meow and just trust that when I type in three at least I'm not not going to get a type error that is I didn't mess up as a programmer with respect to the types of my variables why because when I wrote the coder in the first place I provided these annotations these hints that inform tools like my piie that my intention had better line up with what the actual code does let me pause here and see if there's now any questions on tight pins or my pie is it common or how common is it for those to be used or is it just that it's more used in more complex code um where it's more difficult to ensure that you're actually uh using the correct type in the way that you're using the variables it's a good question and it's rather a matter of opinion python was designed to be a little more versatile and flexible when it comes to some of these details partly for uh writeability to make it easier and faster to write code partly for performance so that the program like python doesn't have to bother checking these kinds of details we can just get right into the code the reality though is that uh strong type checks do tend to be a good thing for the correctness of your code why because programs like mypie can find before your code is even run if there's already known to be an error and it tends to be good for defensive programming um so the the situation essentially is that within the python ecosystem you can uh annotate your types in this way you can use tools to use those typin but to date python itself does not enforce or expect to enforce these conventions in larger code bases in professional code bases Commercial Code bases probably depending on the product uh project manager or depending on the engineering team they may very well want themselves to be using typ pins why if it just decreases the probability of bugs in fact let me propose now that I imagine a situation where instead of expecting that meow prints meow meow meow some number of times suppose that I accidentally uh assume that the meow function just returns returns meow some number of times we saw for instance when focusing on unit tests that it tends to be a good thing to have functions that return values be it an INT or a string rather than just having some side effect like printing things out themselves so perhaps I'm still in that mindset and I've just assumed mistakenly for the moment that meow returns a value like meow or meow meow or meow meow meow a big string of some number of meows rather than just printing it itself as it clearly does at the moment on line three and therefore suppos that I accidentally did something like this rather than just getting the number and passing it to meow suppose I did this uh suppose I declared a number of a new variable called meows the type of which I think should be stir and suppose again I assume accidentally that meow returns to me a string of those meows so that I myself can then print them later this would be a little more conducive arguably to testing my meow function why because I could expect that it's return rning meow or meow meow or meow meow meow separated by new lines returning a stir that I could then assert equals what I expect it to be in something like a unit test I'm not going to bother writing any unit tests now but let's just suppose that's the mindset I'm now in and so on line seven I'm assuming that I want to assign the return value of meow to a new variable called meow's which I've annotated with this type hint as being a stir just so we can see another variable this one's not an INT but to stir instead well let me go ahead and run this code now python of meow. enter typing in three and you'll see a curious bug meow meow meow none well why is that well it turns out at the moment my meow function only has a side effect it just prints out meow some number of times it doesn't explicitly return a value as it would if there were literally the return keyword there by default then when a function in Python does not explicitly return a value it's implicit return value is effect none and so what we're seeing here is this on line 8 because I'm assigning the return value of meow which is none to my meow's variable line three is what's still printing meow meow meow and line eight is what's now incorrectly printing none because I accidentally thought that meow returns a value but it doesn't so its return value is effectively none so I'm printing very weirdly the word none at the bottom so how could I go about catching this kind of mistake too like I might make this mistake but maybe with less frequency if I'm in the habit of annotating my code with this new feature called co uh typ Pence what you can do here is this let me clear my terminal window to get rid of that artifact and up here let me additionally specify with some funny looking syntax that my meow function actually by Design returns none so you literally use this arrow notation in Python when hinting what the return value of a function is you would do this after the parentheses a space a hyphen a greater than symbol like an arrow and then another space and then the type of the return value for now it's indeed going to excuse me return none but now at least I can catch it like this if I now run not python but my P on my code which would be a habit I'm now getting into if using typ hints check that I'm using all of my types correctly before I even run my program we'll see that now my Pie has found on line seven that meow quote unquote does not return a value and my Pi knows that because I have proactively annotated my meow function as having none as its return value so now my piie can detect that I should now realize oh wait a minute I'm being uh foolish here ma meow clearly does not return a value I should not be treating it like it does on line seven let me go about actually fixing this now so how do I go about fixing this well let's practice what we preached in our focus on unit tests having a function like meow not have side effects like printing itself but let's have it return the actual string and I can actually do this kind of cleanly let me uh clear my error message in my terminal window here let me get rid of the loop here let me say this time that okay fine meow is going to return a value an actual stir or string so I've changed none to stir and now I can implement this in any number of ways maybe even using a loop but recall that we have this syntax in Python which will I think solve this problem for us if I want to return a string of n meows what I can actually do recall is this return quote unquote meow back sln times that number n so it's kind of a clever oneliner avoids the need for a for Loop or something more involved than that to just say multiply meow back sln against itself three times ENT or end times in this case in general so that I get back a big string of zero meows One Two Three or many more meows instead I think now my code on line six is actually correct now I've changed meow to behave the way I was pretending to assume it always worked so I'm storing in meow's plural a variable that's of type stir because now meow does have a return value of type stir itself per this typ hint as well all right let me go ahead now and print meows but because each of my meows comes with a a trailing new line the back slash n I'm going to proactively fix what would be a minor aesthetic bug and I'm just going to avoid outputting an extra new line at the end of those uh three so if I run python of meow. py now type in three there's my meow meow meow and now no mention of none questions now on typ hints and these annot and mypie and using them to defensively write code that just decreases hopefully the probability of your own bugs in the return there is a in return there is a double quotes that have meow sln why the program don't take it as a strange why does the program not take it as a a a strange see so so recall that um early on in the class we looked at plus as a concatenation operator that allows you to join a string on the left and the right multiplication is also an overloaded operator for Strings whereby if you have a string on the left and an INT on the right it will multiply the string so to speak by concatenating or joining that many meows all together so this is a feature of object-oriented programming an OB an operator overloading as we saw it uh in the past other questions on typ Pence or mypod can we not type cast this data type of the you know of this variable number no you still and let me correct the terminology it wouldn't be called type casting in this context uh because it's not like C or C++ where there's an equivalence between these types you're technically converting on line five a stir to an INT you do still have to do this because my piie for instance would yell at you if you were trying to assign a stir on the right to an INT on the left you must still use the int function int it's self is still a function it's not a type hint but the word int is being used in another way now in these type hints so this int is still a function call as it always has been this syntax on the left is another use of the keyword int but in the form of these type hint so you still have to do the conversion yourself all right let me propose that we transition to another feature of python that's worth knowing especially since it's one that you'll see in the wild when you see code or libraries that other folks have written namely something known as a dock string or document strings it turns out in the world of python there is a standardized way per another pep python enhancement proposal this one 257 that essentially standardizes how you should document your functions among other aspects of your code and so for instance let me go back to my uh meow. py file here and let me propose that we now start documenting this code too so that I know what the meow function does and in fact the standard way of doing this using dock string notation would be as follows to comment this function not above it as you might be in the habit of doing with code in general but actually inside of it but instead of commenting it like this with the usual hash comment sign like meow n times it turns out that when you're formally docking when you're formally documenting a function like meow in this case you don't use regular inline comment so to speak you use this syntax instead you use triple quotation marks either double or single then you write out your comment meow and times and then you write the same again at the end so either three double quotes at the start and the end or three single quotes at the start and the end and python has built into it certain tools and certain assumptions that if it detects that there is a comment using this dock string format triple quotes on the left and the right it will assume that that's indeed the doc mentation for that function and it turns out in the pyth python ecosystem there's a lot of tools that you can then use to analyze your code automatically extract all of these document strings for you and even generate web pages or PDFs of documentation for your own function so there's these conventions via which if you adhere to them you can start documenting your code as for other people by generating automatically the documentation from your own code without writing something up from scratch man manually now it turns out if your function uh does take arguments and perhaps does a bit more there are multiple conventions for how you can document for the human programmers that might be using your function whether it's you or a colleague or someone else on the internet to actually use these doc strings to standardize the information they're in so you might see this instead using these same triple quotes above and below now you might see your one sentence uh one sentence explanation of the function meow meow and times uh sometimes depending on the style in use it might actually still be on the first line but with a blank line below it but I'll keep everything uniformly indented and this is a convention used by some popular python documentation tools as well you would say syntax like this Pam n colon and then a description of what n is number of times to meow then colon Type n colon int which just indicates that the type of n is an integer then if this function could actually raise an exception you can document that too and actually it's not really well it's arguably my mistake here if n comes in as an argument and is not in fact an INT maybe it's a float or a string or something else the multiplication sign here is not going to work it's not going to multiply the string it's going to trigger what I know from experience to be a type error so I'm going to go ahead and proactively say in my own documentation that this function technically if you use it wrong could raise a type error even though I'm hinting up here with this annotation that you should pass in an INT again python doesn't enforce that so if you pass in a float this might in fact raise this function a type error and so that might happen if n is not an INT and then lastly I might say for clarity sake for other programmers this function returns a string of n meow one per line and the return type of that value R type is going to be now all of this syntax here as I've used it is not python per se this is a convention known as restructured text which is a form of markdown like language that's used for documentation for websites for blogs and even more but it's one of the popular conventions within the world of python to document your own functions so this does not have anything to do fundamentally with type hints type hints are a feature of python what I'm doing here is just adhering to a third party convention of putting in between a Python doc string from the start to the end a certain standard format so that these third-party tools can analyze my code for me top to bottom left to right and ideally generate documentation for me it can generate a PDF a web page or something else so that I or my colleagues don't need to not just only write code but also manually create documentation for our code we can keep everything together and use tools to generate the same for us any questions now on these dock strings which again are a Convention of documenting your own code often following some standard syntax yeah so when you say like you would document it and put it in a PDF is the purpose of doing this to kind of like publish it and share your function so other users can use it absolutely in the past when we have installed some thirdparty libraries for instance cow a few weeks back call that I showed you what functions it had but if you read the documentation you might actually see that uh it was documented for us by the author of that program now I don't believe they were using this particular syntax but it was definitely useful for you and me to be able to read some web page or PDF telling us how to use the library rather than wasting time reading through someone else's code and trying to infer what functions exist and how to use them it just tends to be much more developer friendly to have proper documentation for our own code or libraries as as well other questions yeah um when with Doc strings when you when it's used to generate like a PDF or whatever does it does it include uh any of the code so if you're referencing in the in your in your comment uh if you're referencing the code in the comment itself might not make sense without seeing the code does it does do these in include it short answer you can do that not in the convention I'm using here but there's actually a clever way to write in your doc strings sample inputs to your functions and Sample outputs for your functions and if you use a different tool that we've not discussed that tool will run your code using those sample inputs it will check that your outputs match your sample outputs and if not the program will yell at you saying you've got a bug somewhere so this is just another way where you can use doc strings to not only document but even catch errors in your code this has been a lot and there's a bit more to go why don't we go ahead here and take a five minute break and we resume we'll take a look at yet another feature of python yet another library to write code faster all right suppose we want to modify this meow program to actually take its input not from the input function and the blinking prompt but from the command line recall in our discussion of libraries that you could use something like cy. RGV to get at commandline arguments that a human has provided when you're running your program so why don't we whip up a version of meow that uses commandline arguments instead of again input so I'm going to go ahead and delete what we've done here thus far and let me propose that we import CIS as we've done in the past and let's do this how about if the user does not type any command line arguments then my program will just meow once just so that it does something visually interesting otherwise let's also give the user an option to specify how many times I want the cat to meow so let's start simple let's first of all go ahead and do this if the length of cy. argv equals equals 1 that is the user only typed the name of the program and nothing else after the uh in their command then let's go ahead and just print out one meow like this uh else for now let's go ahead and print out something like this else go ahead and print out let's say usage for the program which will be usage of meow. py just so that the user knows that the program itself is called meow. py all right now let me go down to my terminal window and start to type python of meow. and at this point notice that the length of cy. argv should indeed be one why well python the name doesn't end up in cy. arv at all ever but meow. Pi the name of the file does and it's going to go in cy. argv 0 but that's only one element so the length of this thing is one there's nothing more to the right so when I hit enter now we should see indeed one meow if I don't cooperate suppose I do something like meow's three enter then I'm going to see a reminder that this is how you use the program and this is a common convention to literally print out the word usage a colon then the name of the program and maybe some explanation of how to use it so I'm keeping it very simple but let's be a little fancier what if I really wanted the user to type in maybe not three but something more sophisticated and in fact when uh controlling programs from the command line it's very common to provide what are often called switches or Flags whereby you pass in something like dashn which semantically means this number of times then off in a space and then something like the number three this still allows me to do other things at the command line if I want but the fact that I've standardized on how I'm providing command line arguments to this program with dashn three is just a more reliable way now of my program knowing what does the three mean it's a little less obvious if I just do meow. ppace 3 well what does the three mean at least with syntax like dn3 especially if you've read the documentation for this program ultimately oh dashn means number of times got it it's a way of passing in two additional arguments but that have some relationship between them so how do I modify my program to understand- N3 well if I'm using CIS like this I could do this L if the length of cy. argv equals this time three because notice there's one two three things at my prompt so cy. arv 0 1 and two three things total separated by spaces if equals 3 and let's be safe and cy. arv bracket 1 equals equals DN then let's go ahead and do this let's go ahead and convert uh cy. arv of two to an integer and assign it to a variable for instance called n and then let's go ahead and do this for uh underscore in the range of n let's go ahead and print out some of these meaps now there's still an opportunity maybe to consolidate my print lines with meow but for now I'm going to keep these ideas separate so I'm going to handle the default case with no arguments up here as before and now more interestingly I'm going to do this to be clear I'm going to check if the user gave me three command line arguments the name of the program- n and a number if indeed the second thing they gave me in cy. arv of1 equals equals uh dasn then I'm going to assume that the next thing CIS V of two is going to be an integer and I'll convert it to such and store it in this variable n and now just using a loop I'm going to print out meow that many times all right so it's kind of a combination of our earlier focus on Loops our earlier focus on command line arguments just creating a program that allow me to claim is representative of how a lot of command line programs work even though we've typically not used many like this but it's very common to configure a program one you're about to run it at the command line with something like these command line arguments like dashn or Dash something else now I'm going to go ahead and hit enter and I think I should see indeed three meows by contrast if I do two at the end I should see two meows if I do one I should see one meow and frankly if I just omit this all together I should see one meow as well because that was my default case earlier and now let me allow us to uh assume that this program eventually gets more more complicated right let's imagine a world where I don't want to support just dasn maybe I want to support- a and-b and- c and d d and a whole lot of others or heck at that point I should maybe give them words so maybe it's Das Dash number it's indeed a convention uh in Computing typically to use single dashes with a single letter like n but use double dashes if you're actually using a whole word like number so the command line argument might be dhn or maybe it's Das Das number but you can imagine just how complicated the code gets if now you want to support dn- A- B- C and so forth you're going to have to be checking all over the place and what if they come in a different order you're going to have to check is dashn first or is it second or is it third or is it fourth I mean this just becomes very painful very quickly just to do something relatively simple like allow the user to pass command line arguments into your program well this is why as always there exist libraries and another library that comes with python that's probably worth knowing something about is this one here called ARG parse in fact with a lot of the tools I myself or cs50's team writes in Python we very frequently use arars whenever they are more complicated than a lot of our class demos and a little more similar to this one where we want to allow the user to pass in configuration options at the command line and by supporting things like dashn or- a or- b or- c arars is a library that per its documentation just handles all all of this parsing so to speak this analysis of command line Arguments for you automatically so you can focus on writing the interesting parts of your program not the command line arguments part so how might we use this well let me go back to vs code here let me clear my terminal window and let me propose that I rewrite this using not CIS but actually using ARG parse and I'm going to start a little simple and then build back up so let me throw all of this away for now and instead import ARG parse uh ARG parse stands for argument parser to parse something means to read it uh kind of pick it apart to analyze it so this is indeed going to do just that for me now let me go ahead and do this and for this Library it's helpful to know a little object-oriented programming like we all now do I'm going to create a variable called parser I could call it anything I want I'm going to set it equal to the return value of ARG parse dot ARG you parser with a capital A and a capital P A Constructor for a class called argument parser that comes with python itself within in this Library here now I'm going to configure this argument parser to know about the specific command line arguments that I myself want to support in my program so I'm going to do this parser do addore argument so that's apparently a method in the parser object I'm going to add an argument of- N Easy enough now I'm going to go ahead and actually parse the command line arguments I'm going to do args or I could call the variable anything I want parser dop parse ARS and by default parse ARS is going to automatically look at cis.org V for me I don't need to import CIS myself I can leave the argument parser uh its code to import CIS look at cy. argv and figure out where dashn or anything else actually is and what's nice now because this line of code here results in the parser having parsed all of the command line arguments I now have this object in this variable called args inside of which are all of the values of those command line arguments no matter what order they appeared in not such a big deal when I've only got one because it's only going to go in one place at the end but if I've got- n- A- B- C you could imagine them being in all different orders they definitely don't have to be alphabetical the user should be able to type them in any order they want that's better for usability ARG parser is going to figure all of that out for me and all I have to do now is this if I want to iterate over that many uh numbers of arguments and that many Ms rather I can do this 4core in the range of the int conversion of args do n so dot is the syntax we kept using to access things like properties inside of an object and that's what args is it's an object returned by the parse ARS function form me I'm going to go ahead now and print out quote unquote meow this many times so it's not super simple like these are three new lines of code I need to write and rather understand but it's already a little simpler and more compact and my if and my L if and my ores and my ANS and all of that Boolean logic it's handling a lot of this for me so if I didn't make any mistakes let me run python now of meow. enter and I did make a mistake here I did make a mistake what's what's wrong here now what's wrong well I definitely didn't run it the way I intend so dhn3 enter so it does work but if I don't cooperate this actually seems to be a worse version if I don't pass in dhn and a number it just errors with a type error int must be a string none is what came back so there's clearly an error here but the library is more flexible I can actually provide some documentation on how to use this thing so how do I know how to use this well typically it's conventional in Python and in a lot of programming environments to run a program with a special argument DH or Das dashel and almost always I will claim you'll then see some kind of usage information indeed that's what I'm looking at now I just ran python of meow. space- I'll do it again let me clear my screen and this time do d-el in English enter and I see the same thing it's not very useful at the moment it just shows me what the usage is up here and this is kind of interesting this is a standard syntax Inu Computing and we've kind of seen it in Python's documentation before this just means that the program's name is of course meow. pie square brackets as almost always in documentation means it's optional so I don't have to type-h but I can I don't have to type-n and another value but I can and then down here is some explanation of these options and more verbally showing me that I can also do Dash dasel and not just Dash but this is so generic this has nothing to do with my program this is not going to help my users when I actually release this software for the world so let me go ahead and improve it let me add a description to my argument parser that the humans will see meow like a cat quote unquote is going to be the value of this named parameter called description and let me also add a help parameter to my dashn argument that just explains what dashn means number of times to meow quote unquote I'm not going to change anything else but I am going to go back to my terminal window and run python of meow uh I'm going to run python of meow. py-h or equivalently d-el and now notice that this is a little more user friendly if I scroll up we still see the same usage but there's a quick sentence in English of explanation that this program meows like a cat and if I look at the options now oh that's what N means it's the number of times to meow and this capital n a middle variable if you will is just indicating to me that I need to type a number by convention after the lowercase dasn so it would be nice though all that said if my program still didn't just break when I run it without any command line arguments right ideally my program would handle this just like my manual version did when I used cy. Arvy myself so we just need to add a little more uh functionality to this library and if I read the documentation I'll see that add argument takes yet another named argument if you want you can specify a default value for dashn for instance one and I'll do that there and you can further specify that it's got to be an INT and what this will additionally allow me to do is if I tell AR parser to make sure that the value of dasn is an INT I don't need to do the conversion manually I can just trust down on line seven that when I access the property called n inside of my args object it's going to be automatically an INT for me and again this is the value of a library let it do all of the work for you so you can get back to focusing on the interesting project at hand whatever problem it is you're trying to solve like in this case granted not that interesting but meowing like a cat let me go ahead now and run python of meow. and hit enter this time no arguments and now it meows why because I specified that if I don't as a user specify dashn it's going to have a default value of one apparently and I don't have to convert that value from a stir to an INT because I told AR parser please just make this an INT for me any questions now on AR pars were really this principle of just Outsourcing the commodity stuff the stuff that everyone's program eventually needs to do so that you can focus on the juicy part yourself what does ARS that end contain what does args do n contain it contains the integer that the human typed after a space after dashn good question other questions yeah did uh uh the the when you specify the type um for the argument uh what happens if does that basically handle the ex C if if the user inputs a string in this case a really good question suppose that the human does not type a number and therefore not an INT well let's see what happen so python of meow. dasn dog where dog is obviously not a number enter and voila we see an automatically generated error message little cryptic admittedly but I'm seeing a reminder of what the usage is and a minor explanation of what is invalid about this and again this is what allows you this is what allows me to like focus on writing actual code we care about and just letting the library automate some of this stuff for us all right well allow me to propose now that we take a look at one other feature of python that we've seen before but it turns out we can use it even more powerfully as our programs become more sophisticated and the problems we're trying to solve themselves become more involved let me go ahead and re uh turn to vs code closing out meow. and creating a new file for instance called unpack. so code of unpack. py and let me just remind us like what we mean by unpacking because this is actually a feature of python that we've seen before for instance suppose that I write a program that prompts the user for their name like David Space men wouldn't it be nice if we could C of sort of split the user's name into two separate variables and when we've done this in the past we've done it in a few different ways but one of them involved unpacking a single value uh that comes back from that like a list or uh some other data structure and putting it immediately into two variables so let's do this here let me go ahead and call uh the input function asking someone what's your name question mark then let me go ahead and just split a little naively on a single space so I'm assuming that the only users at the moment are people like me David Space men no middle names no multiple names it's just one and two which itself could be buggy for other users but for now I'm keeping it simple just to remind us that I can now unpack that return value with something like first underscore last equals the return value of input and now I can go ahead and do something like this like printing out with an F string hello comma and then in curly braces first if I just want to greet myself or any other user as hello David without the last name and frankly if I'm not using the last name recall that a python convention is just to name it underscore to make clear that you know you're not using that value but it does need to be there because you're unpacking two values at once so if I run this it won't be all that unfamiliar I'm just going to run now python of unpack. I'll type in David maen which has a single space and there we have it hello comma David well it turns out that there's other ways to unpack values and there's other features that python offers especially when it comes to defining and using functions and this is slightly more intermediate functionality if you will that's useful because you can start to write even more elegant and Powerful code once you get comfortable with syntax like this so let me go ahead and propose that we not just play with Hello uh uh hello names anymore but instead do something maybe involving some coinage again so maybe not dollars and cents but maybe again as in the past some gallions and sickles and canuts with among which there's a mathematical relationship as to how many of those in the Wizarding World equal each other and let me go ahead and do this let me Define a simple function called total that just tells me the total value of someone's vault in grots The Wizarding Bank based on how many gallan sickles and canuts that they have which again are currencies from The Wizarding World as opposed to our actual human world so this total function might take a variable like gallions and sickles and canuts like this and then it's going to return the formula which I admittedly had a look up myself and it turns out that the formula for converting gallions and sickles to Kuts would be this gallions times 17 plus sickles then times all of that by 29 and then add in the individual canuts not sure in what detail this came up in the uh books or movies but here we have it the official formula all right now let's go ahead and do this let me go ahead and call the total function with just some sample inputs suppose that someone like Harry has 100 gallions 50 sickles and 25 canuts let me go ahead and print that out on the screen all right well if total returns an integer which I think this arithmetic expression will do let me go ahead and store uh rather pass the return value of total to print and then just for clarity let me write canuts at the end so I know that the unit of measure here is indeed canuts in total all right now let me go ahead in my terminal window and run python of unpack. and hit enter and it turns out mathematically that if I got my math correct 100 gallions plus 50 sickles plus uh 25 canuts equals in total 50775 canuts just avoiding having to use our own human currency here but I'm not doing anything along the lines of unpacking at least just yet let me propose now that I do this just for the sake of discussion let me propose that I leave the total function as is but let me go ahead and just store all of my coins in a list so coins in order from left to right 100 50 25 it just because for whatever purposes in this story I have all of my coinage in a a list in this order kind of a a purse or wallet of sorts well how can I pass this in well I'm not going to hardcode the same values twice just for the sake of discussion how could I pass in the individual elements of a list to my total function well of course I could treat this list as I always do uh using numeric indices by doing coins bracket zero coins bracket one coins bracket two so this is old school stuff with lists if I've got a list called coins and there's three elements the indices or indexes of those elements are zero 1 and two respectively from left to right so all I'm doing here now is passing in the first element from that list as gallions the second element of that list as sickles and the third element of this list as my canuts and that lines up with of course the signature of this function which as total expects that I've passed in those three things in that order left to right all right let me go ahead and run just to make sure I haven't broken anything unpack. piy and hit enter and the math still checks out but this is getting a little verbose a little verbose and wouldn't it be nice if I could just pass the list of coins to this total function wouldn't it be nice if I could just say something like this coins but let me pause and ask the group why would this not actually work as is it technically is passing in all three but why would I get some kind of error when I run this Eric uh because you are passing a list to gallion yeah I'm passing a list to gallion and nothing for sickles and canuts and notice those don't have default values there's no equal signs on that first line of code code which means Python's not going to know what value should be assumed there so it just seems like it's not going to work plus it's the wrong type as Eric notes it's a list and it's not an integer as it was before so let's actually run this incorrect version python of unpacked High enter type error and that is probably what you might expect like I'm messing up with the types here and I I'm required to pass in two positional arguments sickles and canuts that were not even passed so I've definitely aired here but it certainly seems fortunate if the only solution to this is to do what I previously did which is index into the first element index into the second element index into the third like you can imagine with bigger fancier functions that take even more arguments this is going to get very verbose and honestly very vulnerable potentially to just mistakes typos on my part but here too is where you can do what's known again as unpacking a value in Python right now a list is kind of packed with multiple values my current list has these three values one 100 50 and 255 respectively but they're all packed up in this one list wouldn't it be nice if I could unpack that list just like I previously unpacked the return value of the stir classes split function into multiple things too and indeed I can do just that python actually allows me to pass in not coins but Star Coins so if you use a single asterisk at the beginning of your variable that will unpack it and it will take one sequence in this case coins of size three and explode it if you will unpack it into three individual arguments no commas are needed python just handles this for you but the effect of passing in Star Coins is to pass in the individual members of that list which in this case are going to be 100 50 and 25 respectively which is perfect because now it's going to line up with gallions sickles canuts respectively so now when I run python of unpack. py we're back in business and the math checks out but I've kind of cleaned up my code by just introducing this new symbol which we've used of course in other context for multiplication and the like but now it's also used for unpacking in this way questions on what we've just done it's a single operator but it's already quite powerful because it allows us to take a data structure and unpack it and pass it in individually does that work for um uh tles sets dicks dictionaries as well tupples yes sets I don't know R Shin I don't know if order is preserved no oh is that no it does not or you know you're checking order is not preserved so it wouldn't work with set does not work with set does not work with set sorry I'm verbally Googling here just to save us some keystrokes so it would work for um enumerations that where order is indeed preserved and we'll see another example in a moment where it actually can be used in a different way for dictionaries which nowadays do preserve order other questions on unpacking in this way yes hi hello uh can you use unpacking to get the value uh for example 10 + 50 + 25 uh instead of a for Loop and then result plus short answer no if you want the individual values you should be just indexing in this case into those specific locations um this is returning multiple values the equivalent of a comma separated list so you would use the earlier approach if you cared about the individual locations how about one other question on unpacking what if uh we have declared we we declar some default values and if you use this Aster coins will it over right or will it uh skip it good question if I heard you right what if for instance the list has four values like this here and you're still unpacking it when it's only three that's expected well let's try it python of unpack. piy enter another type error this time it takes three positional arguments but four were given so the onus is on us as the programmer not to do that in this case so potentially fragile but avoidable if I'm controlling the contents of this list in fact let me propose now that we take a look at another variant of this whereby we use not just position IAL uh arguments whereby we trust that the first is gallions the second is sickles the third is canuts suppose that we actually passed in the names as we're allowed to do in Python and then technically we could pass them in in any order and python would figure it out using named parameters instead well how might I do this well it's going to be a bit of a regression at first so let me get rid of this list here let me change this now to just manually pass in the values I care about gallions I want to still equal 100 sickles I want to equal 50 and nuts I want to equal 25 so this is old school parameter pressing it's no longer positional I'm explicitly specifying the names of these arguments but that's just going to work because that's exactly what the names of these parameters are in my total function as before let's make sure I nonetheless did not break anything let's run python of uh of unpack. piy enter and there we have it still 50775 canuts well once you start giving things names and values names and values that probably should bring to mind one of our most versatile data structures in Python and even other languages that of a dictionary remember that a dictionary is just a collection of key value pairs names and their respective values so this kind of opens up an opportunity what if I did this what if I actually had for some reason in my program on a variable as before called coins but instead of making it a list of three values like before what if it's a proper dictionary so what if it's gallions quote unquote colon 100 for 100 of those sickles quote unquote and 50 of those and Kuts quote unquote 25 of those each of those separated by uh colons and let me fix my square brackets to this time be curly braces which recall is the symbol we use for dictionaries or dict objects in Python so now I have a dictionary called coins not a list it's a collection of keys and values three keys gallions sickles canuts and three values 100 50 25 respectively if I were to now pass these individual values into my total function I could do it as always with my dictionary so I'm doing it old school now coins is the name of my dictionary I index into it not with numbers like with lists but with words so gallions strings like this uh coins quote unquote sickles in square brackets there and then lastly coins square brackets quote unquote canuts so it's getting it's verbose again like this is not maybe the best road to go down but we'll backpedal in a moment this is just how if you happen to have all of your coins stored in a dictionary you could pass the gallion sickles and canuts into your function respectively let's make sure I didn't break anything let's rerun python of unpack. py and we're still good now how could we get to a situation like this well as always imagine this program is a little longer than this one here and somehow you're using a dictionary maybe just to keep track of someone's purse or wallet like how many coins of each type that they have and as such it's perfectly reasonable to use a dictionary but then you want to print out the total and darn it if that total function does not expect a dictionary so you cannot just do something nice and simple like pass in coins for reasons we saw earlier that would be a type error total expects three arguments three integers you can't just pass in a dictionary but if that's the data structure you're using to store the person's purse or wallet well it's kind of unfortunate that we have this clash between these data types well here's what we can do we can't pass in coins because watch if I try doing that and run python of unpack. we're getting another type error missing two required positional arguments sickles and canuts I have to pass in three things but wonderfully python allows you to unpack dictionaries as well for a dictionary you don't use a single as risk you use two and what this syntax has the effect of doing is passing in three values with names it has the effect of passing in gallion equals 100 comma sickles equals 50 comma canuts equals 25 and so it has the similar effect to the list unpacking but that just passed in the values 100 50 25 separated by commas in effect when unpacking a dictionary it passes in the keys and the values separated conceptually with equal signs just like our function expects so if I now run python of unpack. again we're still good but we've tightened our code up again and now I'm giving myself yet another option I can either store a Wizard's purse or or uh wallets in their uh in a list as we did earlier or I can store it a little more vers uh with even more specificity using a dictionary instead and so do be clear let me rewind star star coins is the same thing if I rewind a little bit to our first example of named arguments is equivalent to what I've highlighted here when you unpack a dictionary it passes in all of the keys and all of the values much like this syntax here but let me tighten it up and go to where we left off questions now on unpacking can we have a in this dictionary uh can we have instead of having a con name value pair can we have a variable number of you know name value pairs short answer yes you can have more than three key value pairs as I have here but it's not going to work unpacking it if the total function is expecting only three so if I were to add something here like let me introduce pennies to The Wizarding World and suppose I have one penny for instance and now I run this same code python of uh unpack. piy where back to a type error again whereby I got an unexpected keyword argument pennies because that is not expected by the total function we will see in just a moment wonderfully a solution though to that but for now it does not work other questions on unpacking with dictionaries or lists in list in list values we gave the same number of arguments and we declared a default value in the function now if you use this as trick will it overwrite that value or will it skip it skip that default value a good question if you if we did have default values up here for instance equals 0 equals 0 equals zero the upside of that recall from our discussion of arguments to functions a while back is that now you don't have to pass in all of those values they will default to those zeros therefore you could pass in fewer than three values either using a list or a dictionary that's unpacked in this scenario I deliberately did not do that because I wanted us to encounter this specific error in this case but you could absolutely go back and add those defaults so it turns out that this single asterisk or this double asterisk is not only used in the context of unpacking that same syntax is actually used as a visual indicator in Python when a function itself might very well take a variable number of arguments that is to say a function can be vartic which means that it doesn't necessarily have to take say three arguments specifically even if they do or don't have default values it can take maybe zero or one or two or three and it turns out the Syntax for implementing the same idea is quite similar in spirit in fact let me go back to vs code here and let me propose that we start over with this code and get rid of our notion of gallions and sickles and canuts and do something just a little more generic just so that we've seen the Syntax for this suppose that I Define a function as follows Define a function let's call it f and that function is not going to take a specific number of arguments but a variable and so I'm going to go ahead and use this syntax here star args which indicates that this function is indeed very adic it takes some variable number of positional arguments positional in the sense that they go typically from left to right but I don't know how many just yet I want to support suppose that I additionally want to support some number of keyword arguments that is named parameters that can be called optionally and individually by their own name well the convention syntactically here would be to use two stars and then K W ARS I could call args or KW args anything else that I want but a convention you'll frequently see in Python's own documentation is that when you have placeholders like this for some number of arguments and some number of keyword arguments um the world tends to use args and key uh KW args well inside of this function let's do something super simple just for now let me go ahead and print out literally quote unquote positional just to indicate to myself while wrapping my mind around what's going on here what the positional argument arents are and let me quite simply print out those args this is not something you would typically do you don't typically just take in these arguments and print them no matter how many there are I'm just doing this diagnostically for now to show you how the syntax works now let me go ahead at the bottom of my file and I won't bother with a main function this time so we can focus only on this function f let me go ahead and just call F with three arguments I'll use the same arguments as before but I'm didn't bother giving them names just yet like gallions and sickles and canuts and the like so what do I have a program that no matter what calls this function f but it first defines F at the top of the file is taking some number of positional arguments some number of named arguments and for the moment I'm just printing out the positional ones let me go ahead and in my terminal window run python of unpack. piy and hit enter and you'll see that the positional arguments passed in are apparently this a sequence 50 25 but notice this if I clear my terminal window there and pass something else like five a fourth argument previously if I try to change the number of arguments I'm passing in to my total function which was only defined as taking three I would have gotten a type error some visual indication that no you can't pass in more or fewer arguments than is actually in the function's definition but now watch if I run python of unpack. Pi this time passing in 15 25 and five a fourth argument all four of those went through just fine I can get rid of all of those but one for instance now rerun my program after clearing my screen and now I'll see just one argument here and even though there's a comma and nothing after it this is actually the syntax when seeing a a tupple in effect whereby The Comma just indicates this is indeed a list but there's only one element therein well let's get a little more curious too let me go ahead and Rewind here to where we started with just those three values and this time let me go ahead and print out my named argument so to speak which is args but KW args again the positional args in this syntax come first the named arguments KW ARS come second uh that's uh what python prescribes so now let me go ahead and not pass in just these numbers let me go ahead and pass in actually named arguments so let me do something now more specifically like gallions equals 100 and sickles equals 50 and canuts equals 25 I'm not going to bother doing any math with total I just want to poke around right now at this functionality of having a variable number of arguments and what's neat now is if I run python of unpack. and hit enter no problem what KW args is is automatically a dictionary that contains all of the named arguments that were passed to my function which is to say when designing your own functions if you want to support more than one argument maybe more than two or three or four maybe a variable number of arguments indeed you can support both a variable number of positional arguments that are just value comma value comma value or any number of named arguments where you actually put the name of the parameter equals the value and then maybe a comma and some more of the same so now it turns out we have seen this before uh in some of the functions we've used to date we didn't necessarily see it called args or necessarily see it called KW ARS but we have seen at least one example of this in the wild recall our old friend print which we've been using now for weeks and when we first looked at the documentation for print way back when it looked a little something like this the first argument to print was objects and I waved my hand at the time at the asteris that was at the start of that variable name but then we had sep for separator the default value of which was a space we had n the default value of which was a new line and then some other named arguments that we waved our hands at then and I'll again do now but what you can now perhaps infer from our emphasis on these asterisks today the single stars or the double stars is that you know what this is the convention in Python's documentation to indicate that print takes a variable number of arguments so if we were to look at the actual implementation of the print function implemented by Python's own authors it might very well look something like this deaf print and then the first argument would be star objects thereby indicating that print takes a variable number of arguments the next one of which might be sep equals quote unquote either using double quotes or as in the documentation single quotes too the next one of which might be end the default value of which is a new line and then some of those other named arguments that we've not looked at as well and then maybe inside of the print function implemented by the authors of python maybe there's a for Loop like for object in objects that allows them to iterate over each of those variable number of objects and print each of them and this is why in programs past you and I have been able to do just print open parenthesis close parenthesis with nothing inside or you and I have been able to print out something like Hello World a single string inside of those parentheses or you and I have been able to do a single string hello and then another string quote unquote World thereby passing in two arguments or even more so we've long had this ability to use vartic AR uh functions whereby you can pass in a variable number of arguments what you now have via this args and KW ARG syntax but again they do not need to be called that is the ability using that star or two stars to implement those kinds of functions yourself my own F function a moment ago did not do anything all that interesting but it hints at how you could if in the future you have a use case for taking zero or one or more of either type of argument any questions now on these types of arguments what will happen if you print quarks and the argument is like a list ah so what would happen if you print the argument like it's a list so I think we saw that if I roll back in my history here to when I had that F function which I called f just to be very generic just so we could play around with the syntax this is what I had here so this is a um I passed in 100 comma 50 comma 25 that gets automatically stored in args and when I run it you can actually see that sequence of values by running python of unpack up high there is that sequence all in the form of one single variable I'm printing it just for Diagnostic purposes this is not really a useful or pretty program but it hints at how we can access that whole sequence of values other questions on this approach here can we pass kws from one function to another function absolutely you can pass either of those to another function which you might want to do if you want to wrap another function provide some additional functionality but still pass in all of the supported arguments to the underlying function as well all right how about this next it turns out that a few other tools we can add to your toolkit relate to the types of programming models that python supports we started out quite some time ago focusing really on procedural programming in Python whereby we wrote code top to bottom left to right defining some functions or if you will procedures along the way defining Vari and having side effects and assigning values as needed but we then eventually introduced or really revealed that python is also very much object oriented and a lot of those variables a lot of those types that we were using all that time were in fact objects objects that were uh came from certain classes and those classes were templates of sorts blueprints via which you could encapsulate both data and functionality therein well we also saw along the way some hints of a third Paradigm of programming that python also to some extent it support which is known as functional programming whereby functions are ever more powerful in that they tend not to have side effects no printing or changing of State globally but rather they're completely self-contained and might take as inputs and return values and that's generally a paradigm we saw when we started sorting things particularly with functions like our sort function or Lambda function when we passed in the function we wanted to use to sort a list way back when well it turns out python has other fun functionality that is reminiscent of functional programming and indeed is a powerful way to solve problems a little more differently still let me propose this let me propose that I whip up a new program here in vs code by closing our unpack. and this time creating another program called yell suppose the goal at hand is to implement some program that allows the user to pass in input and then it yells the response by forcing everything to uppercase my apologies to those with with headphones there I'll I'll modulate so let me go ahead and run code of yell. pi and within yell. Pi let's go ahead and Implement a program that really does just that let's go ahead and Define a main function up here and let's assume for the moment that this yell function already exists and yell something like this is cs-50 properly capitalized not in all caps now let's go ahead and implement this yell function with deaf yell it's going to take for now a single uh word or phrase uh and let's go ahead and I'll call it phrase here and I'm going to go ahead and just print out the phrase. uper so phrase. upper is going to force the whole thing to uppercase and as usual down here if the name of this file equals equals quote unquote uh main then let's go ahead as always and call Main so let's just run this but for the most part it should be fairly straightforward when I run python of yell. py this is cs50 is yelled on the screen all right that's nice but it's not great that yell only expects a single uh expects a single phrase wouldn't it be nice like print if I could pass in one phrase or two or three or really multiple words more generally but as individual words themselves so let me retool this a little bit and change yel to take in not a phrase but how about something like a list of words so that ultimately I can call Yell like this uh quote unquote this inside of a list quote unquote this inside of a list and quote unquote cs50 inside of a list I'm not going to bother with typ pen answer annotations for now but I'll just assume that yel has been defined now is taking a list of words as defined here but now I want to force them all to lowercase so I don't quite want to do something as simple as this like for word in words I could for instance print that given word and maybe end the line with nothing right now but I think if I do this python of yell. no that's that's not right I haven't forced anything to uppercase so let's fix this well let's go ahead and do the following let me go ahead and accumulate the uppercase words as follows let me create a variable called uppercase and initialize it to an empty list using square brackets or or more verbose list syntax and now let me go ahead and iterate over each of those words in Words and for each of them let's go into our uppercase list append to it the current words uppercase version so this is a way of creating a new list called uppercase that is just appending appending appending to that list each of the current words in the loop but uppercased instead and now just let me go ahead and print out the uppercase list this isn't quite right let's see what happens here python of yelpy okay it's not quite right because I don't think I want those quotes or those square brackets what am I seeing I'm actually printing a list but but but here's where some of our unpacking syntax now can be useful I don't have to change my approach to this problem I can just unpack uppercase by adding a single star and now let me go ahead and rerun python of yelpy and now it's actually just English there's no remnants of python syntax like the quotes and the commas and the square brackets I've now unpacked this is cs50 as three separate arguments to print so already now this unpacking technique would seem to be useful well it's a little unfortunate that I now need to call Yell though with a list of values in this way this is just not the norm or at least it's not nearly as user friendly as something like the print function where I can pass in zero or one or two or three or any number of arguments why are you making me for your yell function pass in only a list well we can do better let's adopt some of the new conventions we've learned and let's go ahead and get rid of the list by removing the square brackets and let's just pass yel three arguments now I don't want to do something like change the definition of words to take in like word one word two like that's not going to scale and it's not going to handle different number of words but we have a technique now we can say star args which will allow the yell function to accept any number of arguments and just for specificity let's not call it generically arcs let's name it something a little more self-explanatory like star words this just means I have a variable number of words being passed in now I think I've made a marginal Improvement let me run this again python of yell. py this is cs50 is in all caps but is just a little better right because now I can treat yel just like I've long treated print pass in as many things as you want and print will deal with it now my yell function is just as powerful it would seem and better still it also forces everything to uppercase well it turns out python comes with this function called map whose purpose in life is to allow you to map that is apply some function to every element of some sequence like a list so for instance if we want to force to Upper case each of the words this is cs50 in the list of words that's been passed in well we essentially want to map the uppercase function to each of those values so using map in Python can I do just that let me go back here to vs code and let me propose now that I reimplement this as follows I get rid of all three of these lines here getting rid of uh that Loop in particular let me still declare a variable called uppercase but let me set it equal to the return value of this new function called map map takes two arguments here in this case the name of a function that I want to map onto a sequence of values well what function do I want to apply to every word that's been passed in well it turns out thanks to my knowledge now of object-oriented programming I know that in the stir class there is a function called upper we've usually called it by using the name of a string variable Dot Upper open paren close paren but if you read the documentation for the stir class you'll see that the function is described indeed as stir. uper I'm not using parentheses open and close at the end of stir. uper because I don't want to call it now I want to pass this function to the map function so that map can somehow add those parentheses so to speak and call it on every one of these words and this is what map does quite powerfully and is an instance indeed of functional programming whereby I'm passing to this map function another function not calling it I'm just passing it in by a reference of sorts and what map is going to do for me is iterate over each of those words call stir. Upper on each of those words and return to me a brand new list containing all of those results together in one list it completely obviates the need for me to do this more manually using that list I'm still going to print the whole thing using star uppercase so that if I get back a three a list of three uppercase words I'm going to unpack them and print them all out so let's run this again python of yelpy enter and voila it's still working but the code now is even more tight uh even tighter than before so it turns out there's another way we can solve this problem in a way that's even more pythonic or at least quite common and that's using a feature known as a list comprehension and it's a a big phrase if you will but it refers to the ability in Python for you to very easily construct a list on the fly without using a loop without calling a pendant a pend but to do everything in one dare say elegant oneliner so how can I go about using this notion of a uh of a list comprehension well let me go ahead and do this in yelpy in vscode here let me go ahead and change my Approach as follows instead of using map which is perfectly fine and correct in this way let me just show you this other way as well a list comprehension is the opportunity to create a list like this using square brackets like this but inside of those square brackets to write a python expression that in effect is going to dynamically generate a brand new list for you using some logic you've written and the approach I might take here is this if I want to store in this list the uppercase version of every word in that word list I can do this word. uper for word inword now this is a mouthful but I dare say python programmers love this capability of being able to Define on the fly a list inside of which is any number of values that you would ordinarily at least as we've done it construct with a loop and again calling a pend and a pend in a pend but that usually takes two three four or more lines this list comprehension that that I've highlighted here is now an alternative way to create the exact same thing a list inside of which are a whole bunch of uppercased words which words for each word in the words list that was passed into yell is what ends up in this list questions on this syntax here it definitely takes a little bit of getting used to because you've got like this value on the left this function call here you've got this Loop inside of the square bracket but if you become accustomed to reading the code in this way from left to right this means give me the uppercase version of the word for each word in my words list questions here on list comprehensions uh can you do conditional so also like if else or uh combine if L if else indeed you can and let me come back to that where we'll see an opportunity to do things conditionally but for now I'm just upper casing every word in the list a good question other questions yeah um is is this is this functional programming or u i mean this particular thing where you saying words do upper for word in word not necessarily this is more of a feature of python I would say yeah map was uh one uh very specific incarnation of thereof our use of Lambda and passing it in as a key attribute to the sort fun sorted function a while back was an example and we're about to see uh one other so we can even use these list comprehensions to filter values in or out of our resulting list so in fact in vs code here let me close yel up high and close my terminal window and let me create a new program here whose purpose in life maybe is to take a same list of students as before with a shorter version thereof and just filter out all of the students in Gryffindor so let me go ahead and create a file called gryffindors dopy I'm going to go ahead and copy paste from before really my list of students at least hermion Harry Ron and Draco from the start here just so that I can focus on uh one student who happens not to be from Slytherin and what I'm going to do here now if I want to filter out only the Gryffindor students let me go ahead and do this let me create another variable called gryffindors which is going to equal the following list and this is going to be a bit of a longer line so I'm going to proactively move my square brackets onto two separate lines and I'm going to create now a list comprehension I want to do this I want this new list called gryffindors to contain every students's name for each student in the students list but but but if the students house equals equals quote unquote Gryffindor so this is nearly identical in spirit to what I just did earlier to create a list comprehension out of each of the words passed to my yell function but here I'm doing so conditionally and so I'm borrowing inspiration from our focus on Loops borrowing some inspiration from our focus on uh conditionals combining that into this same square bracket notation so that what gryffindors ultimately is is zero or more students names and the names that are included are the result of iterating over each of those students and only including in the final result these students whose house happens to be Gryffindor so when I go ahead and run this with python of gryffindors dopy and hit enter you'll see huh nothing actually happened here well that's because I didn't finish the program let me go and actually finish the program with this how about for each Gryffindor in Gryffindor plural and better yet so that it's sensible that I did all of this work in advance let me go ahead and sort all of those names with our familiar sorted function let's go ahead now and print out each of these gryffindors so now notice if familiar with the books and the movies you'll know that only three of these four students are actually in Gryffindor and if I run python of Gryffindor dopy there we see Harry Hermione and Ron but now in sorted order as well so that's just one way we can solve this same problem using not just a list comprehension but a list comprehension that has this conditional therein but there's yet other ways to solve this same problem too and we come back to some functional features of python in addition to functions like Map There's also this one called filter that can be used to achieve the same effect but with a more functional approach if you will let me go back to vs code here and with the same example let me do this let me leave the original list up above as before including Draco who's not in fact from Gryffindor and let me temporarily Define a function called is Gryffindor that takes in as uh value something uh like a student s and then let's do this let's go ahead and say if s quote unquote house equals equals Gryffindor then go ahead and return true otherwise go ahead and return false now we've seen before conditionals like this that are a bit unnecessarily verbose I don't need to have a conditional if I'm already asking a Boolean question up here so I can actually tighten this up as we've done in the past and just return does the student's house equal equal Gryffindor either it does and it's true or it doesn't and it's false I don't need to explicitly return true or false I can just return the value of that Boolean let's go ahead now and do this I'm going to create as before a variable called gryffindors a list for all of my Gryffindor students that equals to this time the result of calling filter filter takes at least two arguments here one of which is the name of a function to call is Gryffindor and I'm going to apply that function to each of the elements of this sequence here so similar in spirit to map I'm passing in a function that's going to be applied to each of the elements in the sequence but map returns one value for each element in the sequence that's how we forced all of the words to uppercase but if I want to conditionally include a student in my resulting gryffindor's list I can use filter instead filter expects its first function to be not something like stir. upper but a function that returns true or false tell me whether or not I should include or not include the current student from the final list and the question being asked is do they live in Gryffindor we're checking the dictionary's house key for that answer and so ultimately I think we'll be left with something quite similar for Gryffindor in the sorted ver let's do for Gryffindor in gryffindors let's go ahead then and print out the current students Gryffindor name it's not going to be sorted just yet but when I run this version here python of Gryffindor stpy and hit enter we're back in business it's unsorted but we have Hermione Harry and Ron but not Draco and if you recall from a few weeks back if we want to sort even a list of dictionaries we can still do that too I can call sort on Gryffindor plural and I can pass in a key and that key can have a Anonymous function AKA a Lambda function that takes in a student as input call it s and then Returns the value s quote unquote name if my goal is to sort by indeed uh students own names if I go ahead now and run python of griffindor dopy I see the same list of students but this time it's sorted so here we've seen two approaches to this particular problem of Gryffindor students whereby we can either use something like a list comprehension and inside of that list comprehension do a bit of filtration including an if conditional as I did or we can take a more functional approach by just using this filter function passing into it the function that I want to make these decisions for me and then include only those for whom true is returned any questions on either of these two approaches uh yeah I just had a question that if we write the code like the previous version where everything is stuffed into one light what the if we check for the style of the code then won't it have a don't it have a problem with it because it's less readable so would a formatter like black have a problem with the style of some of this code the previous one where the everything was stupped into one line oh a good question would something like black have a problem with this code well let me rewind to that version which was using the somewhat longer uh list comprehension which looked like if we go far enough back give me a few more undos which looked like this ultimately let me go ahead and run black on gryffindors dopy and you'll see that I actually it reformatted ever so slightly but I proactively fixed this myself had I done this and done it on just one line but I knew that black might not like that it would have fixed it for me so I just proactively fixed it before writing the code myself how about time for one other question on gryffindors high in this approach of using a list comprehension or filter yeah when when using filter instead of calling the function is Ginder can you use it ER right there inside filter can you use the function is Gryffindor so you don't want to call it like this because you don't want to call it then you want filter to call the function for you if that's what you mean so I pass it in only by its name instead no I me if you can write the return as house equals equals the inside F yes indeed in fact so recall that we indeed used these Lambda functions way back when when we wanted to pass in a quick and dirty function anonymously to allow sorted to filter by a different key of a dictionary we can do that here I can actually take the essence of this is griffindor function I can change the name of this function in my filter call to be another Lambda function passing in an argument like s and returning exactly that I can now delete my is Gryffindor function all together and now when I run python of gryffindors dopy I still get the same answer and I've not bothered defining a function only to then use it in one and only one place well let me propose too that we equip you with one other tool for your toolkit namely dictionary comprehensions as well and admittedly the syntax is starting to get even weirder but as you get more comfortable with all of these Primitives and others these are just tools that you can optionally but perhaps powerfully use to solve future problems down the road and with a dictionary comprehension we have the ability to create on the fly a dictionary with keys and some values without having to do it sort of old school by com creating an empty dictionary and creating a for Loop and iterating over that Loop and inserting more and more keys and values into the dictionary we can rather do it all at once so in fact let me go back to vs Cod here and let me propose now that I do this let me go ahead and initially do it the oldfashioned way here as follows let me go ahead and simplify and get rid of the houses Al together so that we can focus for now just on a list of students names I'm going to go ahead and run students uh I'm going to go ahead and write students equals quote unquote hermion quote unquote Harry and we'll keep it even shorter this time quote unquote Ron only those three students in Gryffindor I'm going to now proactively as we've done in the past give myself an empty list so that I have something to accumulate some answers to this problem in and now I'm going to do something like this for student in students so I can iterate over each of them let's go ahead and with the gryffindors list append to it the name of the students so quote unquote name and then student which is indeed their name from that list and now let's go ahead and just put these students all in Gryffindor I know these three students are in Gryffindor so suppose that the problem at hand is that I want to build up a list of dictionaries that only contains the Gryffindor students so it's sort of a step back from the previous version where I already had the names and the houses for now just assume that the problem is I have all of their names but I don't yet have the student dictionaries themselves so I'm rebuilding that same structure that I previously took for granted now let's go ahead and just for the sake of discussion just print out these gryffindors so we can see what we've built if I run python of gryffindors dopy in my prompt I see a bit of a cryptic syntax but again look for our little hints I've got a square bracket at the end and a square bracket at the beginning and that indicates as always this is a list I then have a whole bunch of curly braces with a whole bunch of quoted keys they happen to be single quotes by convention when using print on a dictionary but that's just a visual indicator that that is my key and the first value thereof is Hermione second key is a house this value thereof is Gryffindor then there's a comma which separates one dict object from the next and if we look past Harry and Gryffindor there's a third a second comma which separates Harry and Gryffindor from Ron and Gryffindor as well so in short here is some code whereby I fairly manually built up with a for Loop and an otherwise initially empty list the same data structure as before minus Draco just for Gryffindor students but here's where again with dictionary comprehensions or really list comprehensions first can we do this a little more succinctly Let Me Clear My terminal window let's get rid of this initially empty list and this for Loop that appends appends appends to it and let's just do this a gryffindors variable will equal the following list comprehension inside of that list I want a dictionary structured with someone's name and their name someone's house and only for now Gryffindor and that's it but I want one of these objects here in these curly braces for each student in students so here too inside of my list comprehension with my square brackets I want an object as indic I want a dictionary as indicated by the curly braces I want each of those dictionaries to have two keys name and house respectively the values thereof are the student's name from earlier here and Gryffindor only which students do I want to create those objects from well for student in students so again on the left I have what I want in the final list and on the right I have a loop and this time no conditional I want all of these students in Gryffindor as their house now let's print this again uh python of gryffindors dopy and hit enter and now we have the exact same output so instead of three lines it's just one it's a little more uh cryptic to read at first glance but once familiar with list comprehensions and this sort of syntax is just another way of solving that same problem what if I want to change this and simplify what if I don't want a list of dictionaries which I now have again per the square brackets I have a list of three objects here what if I just want one bigger dictionary inside of which is a key like Hermione colon Gryffindor Harry colen Gryffindor Ron colen Gryffindor I don't need a list I don't need separate objects per student I just want instead one big dictionary where the keys are the students names and the values of their house and I'm assuming for now no one's going to have the same first name in this world well I can do this let me get rid of this here and not create a list comprehension but again this thing known as a dictionary comprehension and the visual indicator or difference here is that instead of being square brackets on the very outside this time it's going to be curly braces instead so inside of these curly braces what do I want every key to be I want every key to be the student's name I want every value for now to be Gryffindor and I want to do this for each student in students and now things are getting really interesting and this is another manifestation of python in some views being very readable from left to right absolutely takes practice and comfort but this is creating a variable called Gryffindor which is going to be a dictionary per these curly braces every key is going to be the name of some student every value is going to be Gryffindor what names of what students well this dictionary comprehension will be be constructed from the list of students one at a time so when I print this now the syntax will look a little different cuz it's not a list of dictionary objects it's just one bigger dictionary object itself but now printing gryffindors gives me Hermione col and Gryffindor Harry colen Gryffindor and Ron colen Gryffindor as well any questions now on what we've called dictionary comprehensions as well [Music] any questions on here no well let's introduce one other function from Python's toolkit followed by one final feature and flourish and then you're off on your way well let's go ahead and think back to this recall some time ago that we had just a simple list of students as we have here Hermione Harry and Ron and for instance way back when we wanted to print out for instance their ranking from 1 to 2 to three unfortunately when you do something like this for student in students you can print out the student's name quite easily of course if I do python of gryffindors dopy I get Hermione Harry Ron in that same order but I don't see any numerical rank I see no number one two or three so I could maybe do this with maybe uh a different type of for Loop instead of this why don't I try this so maybe I could do for I in the range of the length of the student list and we've done something like this before and then I could print out I and I could print out the student's name by indexing into that list at location I well what does this look like if I run python of gryffindors dopy it's close uh but you know these aren't programmers they don't necessarily think of themselves as zero index termy probably wants to be first not zero so how can we fix this well just a little bit of arithmetic I could print out i+ one of course and then the student's name so if I clear my terminal window and run python of griffindor high once more now we have this enumeration 1 two three of each of these students but it turns out that python actually has had all this time another built-in function that you might Now find useful that is namely enumerate and enumerate allows you to solve this kind of problem much more simply by iterating over some sequence but finding out not each value one at a time but both the value one at a time and the index thereof it gives you back two answers at once so if I go back to VSS code here now and take this approach I don't need to do this this complicated range and length and then I all over the place I can more succinctly do this I can say for I comma student in the enumerate return value passing in students so this gives me back an enumeration if you will and now I can go about printing I + one as before and I can print out the student so I don't need to index into the list with bracket I notation I don't need to call range I don't need to call length again enumerate takes a sequence of values like these students and it allows me to get back the current index 012 and the current value Hermione Harry Ron respectively so now just tighten things up further and indeed that's been our theme here can we solve the same problems as we've been solving for weeks but tighten things up using just more of this tool kit allow us to equip you with one final tool for your toolkit namely this ability to to generate values in Python from functions this is not a problem that we've necessarily encountered before but it turns out if you're writing a function that reads or generates lots of data your function your program your computer might very well run out of memory and your program might not be able to run any further but it turns out there's a solution to this problem that's something you might have in your back pocket particularly if after this course you start crunching quite a few numbers and analyzing all the more data in fact let's go back to vs code here and let's go ahead and create a program that's perhaps timely at this time of day particularly depending on your time zone you might be feeling all the more sleepy but here in the US it's quite common to be lulled to sleep when you're struggling otherwise by counting sheep in your head and typically as depicted in cartoons you might see in your mind's eye one sheep jumping over a fence and then two and then three sheep and then four and then eventually you presumably get so bored counting these sheep you actually do fall asleep so in vs code here let's create a program called sleep.i that allows me to print out out some number of sheep as though I'm counting them in my mind's eye and Via this program let's do this let's prompt the user for a variable n setting it equal to the integer conversion of the return value of input asking the user what's n for how many sheep do they want to try counting and then let's do a familiar for Loop here and we'll start counting from zero as always so we'll first have zero sheep then one sheep then two sheep and so on for I in the range of that value n Go ahead and print out and I'll paste here an emoji representing a sheep time I so the first iteration I'll see Zero sheep the second iteration I'll see one and then two and then however many uh specified by n ultimately minus one all right let's go down into my terminal window here and run python of sleep. and I should see indeed after typing in say three for my value of n zero sheep then one sheep then two sheep and so forth and if I make my terminal window even bigger here we can of course do many more than this typing in for instance 10 and you'll see that we get more and more sheep as time passes presumably becoming all the more tedious to Envision in my mind's eye so let's now go ahead and uh practice what we've been preaching when it comes to the design of this program and see if and when we actually run into a problem let me go ahead here now and put all of this in a main function by defining main up here as always let me go ahead and indent all of this code here and then let me just do this conditionally as always if the name of this file equals equals quote unquote main let's go ahead and call Main let's make sure I didn't break anything just yet even though functionally this should be nearly the same and if I type in three I still have zero then one then two sheep on the screen but we've been in the habit of course of creating helper functions for ourselves that is factoring our code in a way that allows us to abstract away certain functionality like uh generating some number of sheep into separate functions so that one they're indeed abstracted and we no longer have to think about how they're implemented and we can even reuse them in projects as in libraries but we've also been in the habit too of now testing those functions as with unit tests so I probably shouldn't keep all of my logic anyway in Main and let's Factor some of this out wouldn't it be nice if I could for instance just call a sheep function uh as by uh taking this line of code here and instead of just printing it here let's print out the return value of a new function called Sheep that tells the function how many sheep to print I in this case let's go down as always and create another function here called Sheep the Sheep function now will take a parameter n that's specifies how many sheep do you want to return and so that we can test this as with a unit test though we won't do that here let me go ahead and not print the number of sheep as via a side effect but let me go ahead and return one of those sheep times n so that the user gets back a whole string of sheep that's the appropriate number to print so here too functionally I don't think we've changed anything too fundamentally python of sleep. typing three still gives us zero then one and then two sheep but now we at least have a framework for focusing on the implementation of this sheep function but it's a little inelegant now that it's still up to the main function to do this iteration we've seen in the past way back in week zero wouldn't it be nice to define a function that actually handles the process of returning the entire string that we want rather than just one row of sheep at a time well I think we can do this why don't I go ahead and change sheep as follows let me go ahead here and uh first create a flock of sheep that's initially empty using an empty list then for I in uh the range of n let's go ahead and append that flock for instance one sheep times I so that I keep adding to this list zero sheep then one sheep then two sheep then three and so forth and then ultimately I'm going to return the whole flock of sheep at once so this is going to return the equivalent of all of those strings of sheep so that eh Maine can handle the print thereof so back up here in Maine let's do this how about for each sheep I'll call it s since sheep is both singular and plural for s in sheep of n which again returns to me a list of all of the sheep the whole flock let's just print out each sheep S one at a time all right so so far so good here I think let me go ahead and run python of sleep. Pi and hit enter what's N3 and that still seems to work just fine but let me get a little uh creative here and see not just three sheep on my screen but maybe 10 rows of sheep and that too seems to work fine let me get a little more adventurous and type in maybe a 100 sheep and it's starting to look ugly to be fair but they're all printing out pretty fast let me go ahead and try again with maybe 1,000 sheep on the screen and they flew by pretty fast it's still pretty messy but they're all there we could count them all up how about not just a th000 but 10,000 sheep well that too seems okay it's it's taking like 10 times as long and that's why you see this flickering on the screen all of the sheep are still printing but but but it's a lot of data being printed if I hang in there a little longer hopefully we'll see all 10,000 sheep coming to pass this is here in the video where will we will speed up time all a real online oh my God this is a lot of sheep there we go okay and now all of my sheep have been printed so it seems to be working just fine well let me just be even more adventurous and okay let me try my luck let me try like uh how about 1 million sheep this time and hit enter huh something's no longer working while we wait for a spoiler here does anyone have any intuition for why my program suddenly stopped printing sheep what is going going wrong in this version wherein I'm generating this really big flock of sheep we might have run out of memory or computation power yeah so maybe we're actually pushing the limits of my Mac my PCS my cloud serers memory or CPU the brains of the computer's capabilities because it's just trying to generate massive massive massive lists of sheep 1 million of those rows of sheep Each of which has a huge number of sheep and it seems that my computer here is honestly just really struggling and this is really unfortunate now because it would seem that even though this program clearly works pretty well for a th sheep 10,000 sheep once you cross some threshold it just stops working alt together or it just takes way too long for the program to be useful anymore but this seems a little silly right because theoretically I should absolutely be able to print all of these same sheep if I just printed one right away then print two right away then print three then four then five it seems that the essence of this problem if I go back to my code is that per my best practices that I'm trying to practice what I'm preaching it seems that the fundamental problem is that I've modularized my code by creating this helper function called Sheep whose purpose in life is to do all of the generation of sheep and then return all of them at once wouldn't it be better and I can actually hear my fan turning on now even just trying to generate these sheep wouldn't it be better then to just print the Sheep one 2 3 four at a time well we could do that but that's really a a step backwards that rather contradicts all of the Lessons Learned of the past few weeks where generally not putting everything in main is a good thing generally having an additional function that you can then test separately with unit test is a good thing do we really need to give up all of those best practices just to print out some sheep and and here fall asleep well it turns out there's a solution to this problem and namely in the form of these generators in Python you can define a function as a generator whereby it can still generate a massive amount of data for your users but you can have it return just a little bit of that data at a time and you yourself can implement the code in almost the same way but you don't have to worry about too much getting returned all at once these two like all features of python are documented in the official documentation therein but what you'll find ultimately that it all boils down down to this keyword here yield up until now when we've been making functions we have been defining functions that return values if at all using the keyword return and indeed if we go back to our code here that's exactly what I've been waiting for I've been waiting to return the whole flock at once unfortunately if you wait too long and here we have it my program was quote unquote killed that is to say my computer got so fed up with how much memory and CPU it was trying to use it just said nope you're not going to run at all and that's unfortunate now my program no longer works for large numbers of sleeps sheeps which is not good if I'm really having trouble falling asleep some night so how can I use yield to solve this problem instead well let me do this instead of building up this massive list of sheep in this big list called flock let's just do this instead let me go ahead and simplify this whole function as follows where by I iterate for I in the range of N and then on each iteration in the past I might have been inclined to use return and return something like one sheep times I but this won't work here right because if you want a million sheep and you start a for Loop saying for I in the range of a million you're going to return accidentally zero sheep right away and then this function is essentially useless you shouldn't return a value in the middle of a loop like this because you're not going to get to any of these subsequent iterations of the loop it's going to iterate once and boom you return but thanks to this other keyword in Python called yield you can tell python to effectively return just one value at a time from this Loop so if I go back to this version of my code here and I say not return but yield this is like saying return one value at a time return one value at a time return one value at a time the four Loop will keep working and I will keep counting from zero to one to two all the way up toward 1 million but each time the function is just going to hand you back a little piece of data it's going to generate so to speak just a little bit of that data not all of the data at once and that's good because my computer has a decent amount of ram certainly enough to fit one row of sheep it just doesn't have enough memory to fit apparently 1 million rows of so many sheep so now if I go to my terminal window and run python of sleep. Pi and hit enter what's in three would still work zero then one and then two let me go ahead and increase the size of this here and run python of sleep.i let's try 1 million as before and hit enter and now I immediately see results I don't think we'll wait for all of these sheep to be printed because then we will literally all be asleep but what you'll notice happening now is the program is not hanging so to speak it's not waiting and waiting and thinking thinking and trying to generate the entire flock at once it's just generating one row of sheep at a time and it's flickering on the screen because there's so many of them and that's all thanks to yield it's generating a little bit of data at a time not all at once any questions now on this feature called generators any questions at all to add one more piece of terminology to the mix just so you've heard it this same feature of uh this same feature here is returning what we'll technically Now call an iterator yield is returning an iterator that allows your own code your own for Loop in Maine to iterate over these generated values one at a time how how does uh this yield uh actually works under under the hood I I mean is it is it using multi trading you can think of the implementation as being asynchronous in this sense whereby the function is uh returning a value immediately and then subsequently giving you back another one as well underneath the hood what's really happening is the generator is just retaining state for you it does not going to run the entire loop from top to bottom and then return a value it's going to do one iteration and yield a result and the python for you is going to suspend the function if you will but remember on what iteration it was so the next time you iterate over it as it's going to happen again and again in this for Loop in main you get back another value again and again so yield returns indeed this thing called an iterator and that iterator can be stepped over as in a loop one element at a time but the language python handles all of that for you so that you don't need to do all of the underlying uh Plumbing yourself how about time for one other question on these generators and iterators as our sheep continue to fly by so in every iteration the program will return to the memory to the system so the program will not crash correct on each iteration it's only returning the one string of sheep that's appropriate for the current value of I it is not trying to return all million rows of the same and therefore it uses really one millionth the amount of memory although that's a bit of an oversimplification all right as these sheep continue to fly across the screen let me now uh go ahead and interrupt this as you might have had to in the past with infinite Loop in your own code even though this isn't infinite it's just really long contrl c will interrupt with your keyboard that program giving me back control of my computer well here we are at the end of cs50's introduction to programming with python and if today in particular of all days felt like a real escalation real quickly realize that these are really these are just additional perhaps optional Tools in your toolkit that you can add to all of the past Lessons Learned so that as you exit from this course and Tackle other courses or projects of your own you have all the more of a mental model and all the more of a toolbox with which to solve those same problems if we think back now just a few weeks ago it was probably in our focus on functions and variables that you first started struggling but now in retrospect if you look back at those problems and those same problem sets odds are those same problems would come all too easily to you now conditionals was the next step in the class wherein we gave you the ability to ask questions and get answers and therefore do things conditionally in your code we came full circle today and you can can see that you can now use those same kinds of conditionals now to do fancier things with list comprehensions and D dictionary comprehensions and the like Loops of course have been omnipresent now for weeks including today as we built up those same structures and of course something can go wrong and exceptions and exception handling was our mechanism for not only catching errors in code but also raising your own exception so that if you're laying the foundation to write code for other people as in the form of libraries you can do that too libraries of course are things you can not only use but now write on your own be it a small module or whole package of code that you want to share with others around the world and even better can you write tests for your own code for your libraries for others code as well so that ultimately you can be all the more confident that not only your code is correct today but if you make a change to your code tomorrow you haven't broken anything at least according to your tests if they continue to pass file IO though meanwhile was a way of now storing data not just in the computer's memory like all of these sheep but actually storing things persistently longer term to dis being in a CSV or something more like a binary file like an image with regular Expressions you then had the ability to express patterns and actually validate data or extract data from information all the more of a useful technique nowadays when so much of the world is trying to analyze and process data at scale some of which might uh in fact be uh quite messy uh from the get-go and then of course most recently object-oriented programming an opportunity to solve the same kinds of problems but with a slightly different perspective a way to encapsulate and to represent real world entities this time in code and today of course Etc with so many other tools that you can add that didn't necessarily fall under any of those earlier umbrellas but are useful functions and data types and techniques just to have again in your back pocket as yet other mechanisms for solving problems as well not just putting everyone to sleep but I thought another way to end might be a little more vocally to try writing one final program together this one using a Library we've seen in the past as well as one other I've taken the liberty of installing a text to speech library on my computer here and I'm going to go ahead perhaps and open a new file here called uh uh say dopy in vs code and I'm going to go ahead here and first import our own friend import cow and I'm going to import this new library here import Pi TT sx3 the python text to speech library and now perit documentation which I read in Advance I'm going to go ahead and create a variable for myself here engine equals pyttsx3 init to initialize that library for text to speech I'm going to then ask the user well what do I want to hear spoken and I might do something like this a variable called this equals the return value of input what's this shall be my simple question and I'm going to keep it this time as a string we've seen how to use C we can do c.ca of this turns out this new library can allow me to use its own to say this as well but then ultimately I'm going to have to run the engine. run and wait just in case it's a long phrase or sentence to be said but that's it in just eight lines of code not only am I apparently going to have a cow appear on the screen to close us out now but also some synthesized text ultimately then we hope with this course that you not only learned python that you've not only learned programming but you've really learned how to solve problems and ultimately how to teach yourself new languages a funny enough I myself only learned python just a few years ago and even though I certainly went through some formal documentation and resources online I mostly learned what I know now and even what I had to learn again for today by just asking lots of questions be it of Google or friends who are more versed in this language than I and so having that instinct having that vocabulary very which to ask questions of others to search for answers to questions you absolutely now have enough of a foundation in Python and programming to go off and stand on your own so you can certainly and you're welcome and encouraged to go on and take other courses in Python and programming specifically but better still as quickly as you can is to find some project that's personally of interest that uses python or some other language because at least from my own experience I tend to learn best and I hope you might too by actually applying these skills not to problems in the classroom but really truly to problems in the real world allow me with all that said to look at my full screen terminal window here run python of s.p crossing my fingers one final time in hopes that I've not made any mistakes or bugs and here we go python of sey prompting me what's this how about we end on this note here this was cs50