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 Malin and it's designed for students with or without prior programming experience who'd like to Learn Python [Music] [Music] foreign [Music] world my name is David Malin 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 Art of programming this course is specifically focused on programming in Python itself at the beginning of the course we'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 away 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'll 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 it 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 disk 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 types 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 object oriented programming a paradigm a way of writing code whereby you can represent in code real world entities and this is an 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 when we equip you with all the more tools for your toolkit an additional building blocks additional vocabulary via which after the 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 n 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 foreign [Music] all right this is cs50's Introduction to programming with python my name is David Malin 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 vs 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 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 enter face 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 dot pi as we'll soon see any program that you write in Python generally has a file name that ends in dot pi 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 go and then just a tab that reminds me of the name of this file hello.pi 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 are you can guess infer what the 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 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 dot Pi 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.pi 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 in one the so-called binary system well if that's the case then something that says prints and parenthesis 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.pi 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.pi but I didn't yet 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 programs 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.pi 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 Prince 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 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 non-zero 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 close 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 out 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 way the language expects it's not going to necessarily run at all so let's do this I'm going to go 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.pi 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 if 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 user friendly 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.pi 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 mentioned 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 vs 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 two because you can also use vs code nowadays for free in the cloud how about one other question here on programming with python or hello world or syntax more generally if it's not possible to run the computer using the terminal window I think I heard is it not if it's possible to run the program without the terminal window 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 GUI 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 and 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 when whatever the actual user's name is well to do this I'm going to go back up to hello.pi and I'm going to add another line of code at the very top that simply says for instance 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 paren close paren 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 prompt 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 altogether 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.pi 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.pi 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 intended 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 hard coded 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 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 for 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 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 in 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 and a variable no matter what I call it I can store that input in that variable so as 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.pi and hit enter that's going to prompt me for my name and let me type in my name David 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 going 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 to 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-a-m-e 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 the contents of that variable that is its so-called value all right let's go ahead and do this here python of hello.pi 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 it 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 vs 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 ask user for their name now I don't have to use that language I don't have to use that 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 slept for quite some time forgotten what it is I did the previous this 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 code'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's 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 as 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 programming of pseudo code pseudocode 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 pseudocode therefore because it's not 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 didn't know what I want to do I could have started today by just writing this in hello.pi 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 pseudocode then I can go in there and say all right how do I ask the user for their name well I can do input quote unquote 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 and let me okay let me now print the person's name so again pseudocode 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-sized tasks all right let me call us 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 work for any type 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 I wanted to ask how I make a server line comment oh how do you do many lines of comments if I'm hearing it 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 printing 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 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 if hello.pi 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.pi 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 before the double quote and that was just for Aesthetics too 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 three 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.pi enter what's your name David enter okay I've kind of over corrected 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 pythonoflo.pi 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 do what's inside of parentheses for 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 many times to solve a certain problem which we can encounter many times in our code you can you 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 comma can 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 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't 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 Str for short for string as you may know if you programmed in other languages people who invent programming languages like to be very 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 use print again to call 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 a 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 close 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 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 the 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 of 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 think we've seen a hint about it let's focus though for a moment on this the print function takes another parameter called end and the default value of that parameter is apparently based on this equal sign and these quotes backslash n and what is backslash 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 backslash n means new line and it's a way textually of indicating if and when 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 backslash n you don't literally see backslash 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 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 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 backslash n 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.pi 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 5 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 n 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 pythonflo.pi 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 DAV ID so not a good 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 python of hello.pi d-a-v-i-d 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.pi 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 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 SCP separator or end end 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 use them by name this may be a weird question but I was wondering uh what if someone wants to like add actually quote 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 all out 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 gonna work actually because you are trying to use quotes to be like friend and finger quotes but you're also trying to end the sentence and if I try running this let's do this pythonf hello.pi 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 ago 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 if hello.pi there we go hello friend but there's another way if you insist on using double quotes as you might want to just because consistent you can also use that backslash character again we saw the backslash 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.pi 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 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 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 wrong 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 if hello.pi enter DAV vid 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 which you do this is a little weird but this is what the World shows if you put a f at the beginning of the string right before the first quote Mark that's a clue to python that oh this is a special string let me format this in a special way for you let me now rerun the program python hello.pi 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 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 user's 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 lower case 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 a 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.pi 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 David and I don't know I hit the space bar a couple more times like it's kind of a mess it's all lower case 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 like this uh name equals name dot strip and what does this do remove white 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 dot 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 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 if I rerun this program python of hello.pi enter I have Davi let's do it again space space space space dab 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 dot 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 if hello.pi enter uh space space space d-a-v-i-d 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 David space Malin 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 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 is 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 me to repeat myself than typing everything manually let me go ahead and hit enter space space space David mail in 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 log uh capitalize user's 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 David space m-a-l-a-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 dab ID space m-a-l-a-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 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 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 is 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 altogether how many functions can be combined like this dot strip dot 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 code is going to start to look really really bad right because the line of code is 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 uh-uh 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 to video 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 there 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 no's why don't we go ahead and call on one of the yeses 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 Fung 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 because it's not available at all 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 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 require 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 substrings 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 what 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 users 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 Malin 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 variables 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 Malin I can just say hello comma first all right let's go ahead and clear my terminal window run python of hello.pi and hit enter I won't bother with any leading white space this time but let me go ahead and type in David space Malin and crossing my fingers 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 them to another very common type of data in Python in programming more generally namely integers otherwise known in Python is int int so just as stir Str is short for string so is INT in Python short for integer well what's an integer well just like in math it's a number like negative two negative one zero one two 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 negative two negative one zero one 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 a different purpose but python supports these symbols and more and python allows you to add numbers together plus subtract numbers 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.pi and then running it in a terminal window one of the features that many people like about python is that it supports this 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 vs code here and let me close hello.pi and let me click on the Little Triangle over here and my terminal a window just to make it much bigger just temporarily for a moment so I'm not creating any dot Pi 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 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 one plus 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 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 and 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 dot Pi so to do that recall I can type code down here and the name of the file I want to create dot Pi enter that gives me a new tab up top so I have already closed hello.piom now in calculator.pi 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 for worse over time let me go ahead and first declare a couple of 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 Plus 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.pi I should see hopefully that 1 plus 2 equals indeed 3. all right so not that surprising and not that interesting and honestly this isn't the most useful program because it's always going to calculate 1 plus 2 equals three 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 you 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 y 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 one 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 2 is going to be Y and of course everyone in agreement 1 plus 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 Anjali 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 typed 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 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-A-L 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 X1 what's X2 and there we go now we have a general purpose calculator that's going to support not just 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 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 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 doing something that's pretty interesting now even though it's a bit of new syntax notice that you can Nest functions 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 parentheses 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 parentheses 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 online too 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 Plus 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.pi enter one and two and we're still getting 3. not 12 or not twelve 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 yeses 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 integers and so we know what to expect from them and also the print argument is more inclusive we avoid too much clutter in the code the lines of code are not very long I don't need to know what Z is because it doesn't exist it just C 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 in function yeah hi uh I think but the earlier version is better because when uh I mean if user can put something else other than ink let's say I mean let's say they type one right and two like so will be it will be easier to debug this version or the this version here or 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 inputted integers when I'm expecting integers and Rose actually pointed 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 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 trade-offs 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 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 altogether 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 and tactical 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 one zero and one a flow 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 vs 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 was 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 that here too python comes with some functionality built in and in fact if we return to this URL from earlier wherein 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 to 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 its positional parameter but notice this syntax and this is a convention in programming or technology more generally generally speaking when you see square brackets and 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 two 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 tenths place or the hundredths place that is one or two digits after the decimal point you could additionally pass in comma 1 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 phase I could do round X Plus 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 Plus 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 each 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 5. 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 if calculator.pi again and let me just add 999 plus 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 one thousand 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 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 US approach here which is periods for decimal points and commas for separators what if I wanted this to be outputted as 1 comma zero zero zero 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 one comma zero zero zero comma zero zero zero 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 too 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 plus one enter okay it's still a thousand so I didn't make anything worse but notice this 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.pi 999 1 and now notice that the number has been automatically formatted for me if I were in a different country or Locale I could 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 you how many decimal points it 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 float 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 a little different from this just doing x divided by 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 calculator dot Pi let's do something like 2 divided by three and of course I get .6666 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 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 on but there is a bound on just how precise 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 0.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 divided by Y which is one argument once the math is done inside of the parentheses 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 2 and then 3.67 so here too we see a way of rounding now not just to a nearest integer but to his nearest number of digits but there's another way to do this here and in fact this evokes our our F F string example again let me go ahead and change this suppose that you didn't remember for 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 of characters I'm going to say 0.2 F and this 2 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 2 and then three we get the exact same thing but again this is just consistent with my claim that in programming 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 sometimes 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 two and then writing it like this let's transition now from focusing on strings 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 vs code here and let me propose that we go back to hello.pi I'm going to reopen hello.pi 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 need 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.pi I think the first line is 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 closed 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 def for Define so here too just as stir is short for string and into short for integer def is short for fine 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 indent 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 vs 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 space cases 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 because 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.pi 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 this 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 in 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 my parameter will be the word to 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 2 just because 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 2 instead of something simpler like X or Y or Z all right well what do I want to do with the word two 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 head here and print out not the person's name manually I'm going to sense 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 2 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 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 2 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 straight let me go ahead and run python if hello.pi 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 2 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 pythonflow.pi 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 functions 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 from 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 y 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.pi notice that as soon as I run The Interpreter python of hello.pi 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 appear 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.pi 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 inside 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 help 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 a name the variable into which I got the user's input but the catch is that name exists now only in Main and so watch what happens when I try to run this version of the program with python hello.pi I hit enter I'm prompted for my name David 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 insofar 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 2 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 vs code here and I think we'll return our attention to calculator dot 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 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 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 users typed in and raise it to the power of 2. so 2 squared would be 4. 3 squared would be 9. 4 squared 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 printing how about x squared 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 squared 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 dot pi foreign I'll see that X is 2 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 times n but it's not enough just to do the math yourself n times 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 say shall be 2 x squared is 4. let me go ahead now and say x is now 3 x squared 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 so the power on the right or it turns out there is in Python a function called pal 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 actions are verbs many of which come built into python that you can just use in your own code we then introduced variables via which you could 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] thank you foreign [Music] this is cs50's Introduction to programming with python my name is David Malin and this week we focus on conditionals conditionals or conditional statements in Python and in other languages are this ability 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 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 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 of copying the thing from the right to the left lastly this last symbol represents not equal to so the exclamation point or bang 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 line 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 vs code and let's go ahead and create a program first called compare.pi 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.pi 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 so jurors but we'd like those integers to come from the user so that we can make 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 converting that ultimately to an INT as well so with this amount 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 is in a very interesting program yet I'm literally just stating the obvious based on the math but it's allowing me to now 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 X getting x equals equals y let's run the code well down here in my terminal window I'm going to run python of compare.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 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 flow chart 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 Boolean 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 1 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 convert urge 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 one and Y is two then no the answer is false one is not greater than y 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 too has a false answer in this case because 1 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 I think that's correct and that particular flow chart 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 1 why 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 well designed too thoughts on in what way this program is arguably not well designed even though it's correct let's see here uh Khalid 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 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 account 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 year 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 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 in English take into account that I'm only going to keep it's 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 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 why 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 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 figured 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 arrow Rose 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 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 2 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 one 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 2 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 one 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 asked two questions but then boom we're done only if x happens to equal y do we actually find ourselves logically getting all the way down to this final L if in my code and pictorially only if x is equal to Y we we find ourselves going all the way down to the third Diamond the third question asking is it equal to why 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 aren't 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 allows 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 if x 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 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 proposed 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 catch-all 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.pi let's do for instance one and two it 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 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 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 is 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 complexity 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 capability it's a 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 in 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 and 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 include X is not equal to y so if we instead want to make sure that it is equal to we can just use hopes else using print quote unquote X is equal to Y and again Y 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 if compare.pi what's X1 what's Y2 okay X is not equal to Y let's do it again but 2 for x 1 for Y X is not equal to Y and one third time how about X is one and Y is One X is now equal to Y now if we want to compare that visually to 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 pictorial 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 1 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 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 we print X is equal to Y else X is not equal to RX perfect recall one of the other symbols we saw in 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 we go ahead and print out 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 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 flow charts 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 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 this 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 plus plus and Java curly braces to connote 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 altogether in vs code whereby I'll go ahead now and create a new program say called grade dot 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.pi to give myself a new file and I'm going to go ahead and start by just getting the user's score again on some assignment or tester 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 hopefully much higher than that like 97 98 99 100 assuming the test or assess is out of 100 percentage points now how could I go about assigning a grade to the student score well in the U.S 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 an 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 express 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's 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 an 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 and score is less than 90. so I'm using less than instead of less than or equal to so I'm making sure that they're 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 all together and we're going to give an f instead for the grade so that's the catch-all 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 c or a d else it's going to 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 submit it at all that's a an F all 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 we're 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 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 plus 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 in 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 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 0 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 80 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 as 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 reach 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 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 alif 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 conditional saying if if if if now our cleverness here of using broader strokes and not using an 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 logically 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'd 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 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 Elton oh I I like your enthusiasm for simplifying things further I'm gonna 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 elif 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 that we'll call parity and Mathematics parity can refer to whether a number is even or odd and that's kind of an interesting question and it turns out it can be useful in other applications too to 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 dot 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 divided by three three does not go into one eat cleanly so you have a remainder of one two divided by three has a remainder of two three divided by three has a remainder of zero because it divides cleanly 4 divided by three 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 5 divided by 3 has a remainder of course of two so that's all we mean by remainder how much is left over after divide 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 zero two four six eight ten twelve fourteen sixteen 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 two four six eight and ten 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 percentage 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 divided by two 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 pythonofparity.pi 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 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 and 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 and then go ahead and print quote unquote even so if this magical function called is even returns true as its return value I am 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 to recall 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 two equals equals 0 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 Bool 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 an 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 percent two equals equals zero that is if n divided by 2 has a remainder of 0 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've 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 parity.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 how about 3 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 name for yesterday and create stuff uh I have just one query like basis on the 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 plus plus 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 dot strip and use it like that good question if you've created your own function can you use other functions like dot strip or dot title or dot capitalize 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 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 plus 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 one more elegant line if you will instead of asking if n divided by 2 has a remainder of 0 return true else returned false let me delete all of that and just say this return true if n divided by 2 has a remainder of 0 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 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 divided by 2 has a remainder of 0 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 parody.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 divided by 2 having a remainder of 0 or not like that is by definition a Boolean expression it has a yes no answer a true false answer well if you're 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 zero if it helps let me add parentheses temporarily because what's going to happen in parentheses will happen first n divided by 2 either does or does not have a 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 parity.pi and let me go ahead and create a new file called house.pi and in house.pi I think what we're going to do is try to implement a program that prompts the user for their name and it 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 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 inputted 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.pi 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 house.pi 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.pi and let's go ahead and type in Padma enter and who because we haven't actually hard-coded 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 check 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 else to catch anyone else all right let me go ahead now and run this version of the program python of house.pi I'll type in Hermione 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 altogether 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 Hogwarts houses so you can imagine that code just 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.pi 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 indent it 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 or 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 gonna 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.pi 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 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 catch-all 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 contexts 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.pi 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 on the same line in 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 Hermione 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 Hermione then another single bar and do quote on 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.pi let's make sure that Harry is still in Gryffindor let's make sure that Hermione 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 tightened 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 elephant elephant eleph 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 catch-all 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 again [Music] thank you all right this is cs50's Introduction to programming with python my name is David Malin and this week we focus on Loops disability 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 vs code and in my terminal window let's go ahead and create uh via code cat.pi 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 print 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.pi 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 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 so 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 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 wanted me out 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 yes 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 that 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 fifty 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 don't 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 wild 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 3. 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 0 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.pi 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 Teemo hi uh I think it's going to continue uh to print out mail since I is always equal to 3 and the wow 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 is 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 timu'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 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 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 Ctrl 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 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 cat.pi and I indeed get three meows why 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 flow charts 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 equals three so if I follow the true line I meow and then I follow this arrow and I update I to equal I minus 1 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 two to one well does one not equal zero well obviously if one is not zero so we meow again we decrement I again I is now zero does zero not equal zero no it equals zero so the answer is false and we stop so there perhaps more so than any of our flow charts 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 one 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 in 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 ourselves 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 I equals I plus one and now notice just for clarity two 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 see 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 ultimate at least 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 plus one and this is because it's such a popular thing to do in code you can instead just say I plus equals one 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 just a convention those of you who have programmed in C C plus plus python not python C C plus plus Java JavaScript 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 for Loops which um have a certain I value initialized to it 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 compare to that in just a moment other questions on Loops using while here so I had a question about the flow charts okay uh there were certainly yeah there were certain symbols for the certain kind of the statements uh sir the artists certainly used for that kind of statement that they are protected they are so I deliberate use anyone I deliberately use certain types of symbols certain shapes here uh whereby an 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 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 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 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 flow charts 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 explore 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 idea in Python we 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 values 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 vs 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 4 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 shorter 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 could kind of in your mind's eye maybe see the gears turning as all of these variables are 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 would automatically update I to equal one 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 map now a total of three times what is the list the list in this program is exactly that zero comma one comma two 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 dot pi 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 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 again we are saying 0 1 2 please subscribed 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 gonna write out one zero through a million or zero through nine uh you know 999 thousand uh 999 999 like no you're not gonna 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 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 his 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 two 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 0 1 and 2 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 two comma three comma four all the way up to 999 999 I just do this so that's got 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 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 that 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 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 wanted 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 you to some of you to me let me run python of cat.pi 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 we can use an escape sequence we should do backslash and amazing yes think back to backslash n 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 backslash in there inside of my quotes So that at the end of every meow there's a new line let's see how this looks Let Me Clear My screen and run python of cat.pi 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 Endeavor 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 backslash and 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 end equals quote unquote so that it's no longer the default backslash n 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 cat.i I 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 backslash n I've got times three I've got and 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 well 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 smelling 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 what's n question mark well I want to check like I could say if n is less than zero like if it's negative well I could do this well then ask again int input what's and 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 conventionally induce an infinite it 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 an infinite Loop is to ask the question you care about like give me an INT 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 as 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 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 one 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 lines six and seven so if I run this now python of cat.pi enter well what's n let's start with 3 where we began 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.pi 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 mailing 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 all 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 three 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.pai meow meow meow it's always going to do three be because I've hard-coded the three well let's make one Improvement here let me go ahead now and maybe do this 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 paren 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 in 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 too 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 and 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 3 which we hard coded 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.pi 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 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 hogwarts.pi 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 get-go 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 stun 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 Harry in quotes because it's a string and then Ron 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 3 earlier but that had three ins zero one two 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 or 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 that location 2 too 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 two 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.pi 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 one to two you can use Python to just iterate over anything not just numbers but strings so I could actually do this 4. 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 four hundred 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.pi 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 down in the down the line you should call your variables what they are so in 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 unreal reasonable 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 uh okay so uh 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 zero one two 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 2 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 0 1 and 2. so I think I can Nest my functions like this this if I first get the length of the students list that's going to be 3 then I pass that return value as the argument to range that's going to give me back a range of value 0 then 1 then 2. 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 two close bracket turns out I can actually put a variable in there and I can express any number inside of those brackets so as to print these all out dynamically in a loop let me do this python of hogwarts.pi enter there's Hermione Harry and Ron and now if I'm just curious 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 Hermione is the top student but she's in zeroth 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 I up here and now we see sort of a top three list of students Hermione 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 or any questions now on on these lists any questions now on these lists this length these ranges or otherwise my question is 4i in range can you explain this once more uh so let me rewind in time we started off doing this for I in 0 1 2 and then we printed 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 lists there are also what are called dictionaries or dicks 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 in 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 well 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 Gryffindor corresponding to Hermione's house 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 value in houses whoever is second in students lives in the second house there's our third Institute 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 Patronus 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 close 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 gonna this is gonna 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 somethings and my values on the right my other somethings 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 Hermione'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 one two Hermione Harry Ron respectively dictionaries allow you to use actual words as your indices so to speak your indexes to get inside of them so if you want to print out Hermione'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 Hermione'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 Hermione 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 bet we can improve this but let me run python on hogwarts.pi 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 Dimensions 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 hard coding 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.pi and hit enter notice what should I say 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 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 student's 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 Hermione's 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 up hogwarts.pi enter now I see Hermione Gryffindor Harry Griffin or 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 Hermione'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 four student in students does uh if I'm just correct me if I'm right does that mean it Imports the list of students and uses the indexes or in other words Hermione 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 is 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 Hermione'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 over a list but rather than indurate over the numeric location 0 1 2 it iterates over the bold-faced 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 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 thing with the student but multiple things as well their name their house and their Patronus in this case well what might code like this look like well let me go back to hogwarts.pi 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 for 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 vs 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 1K 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 this same student is going to have a third key called Patronus 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 it's 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 Patronus what are the definitions of those words for Hermione Hermione Gryffindor 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 a house here is again going to be Gryffindor and this one I I knew his Patronus 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 how to look this one up Ron's Patronus 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 Draco 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 key word 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 Patronus 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 too the syntax is our clue because this line 2 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 kept it all together here this time but how many keys does this first dictionary have put another way in Hermione's physical dictionary how many words are in that dictionary three the words are name house and Patronus what are the three definitions or values of those words in Hermione'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 for student and students is just going to iterate over every student in the list one two three four 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 Prince arguments student Open Bracket House close bracket all right let's go ahead and run this python of hogwarts.pi 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 and 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 Patronus 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 and a house but a Patronus 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 yesteryear at least for me wherein 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 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 o.pi 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.pi 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 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 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 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 you 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 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 generically speaking a parameter called height I could call it n or H but I'll be a little more explicit now with Heights 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.pi 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 re-implement now print column in different ways especially if I'm 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 of 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 miro.pi 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 Mario encounters these bricks in the sky that if he jumps up underneath they become coins and so he he gains to his 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 vs code here and let me propose that within vs code here just like before we try to abstract this away so let me go ahead and get rid of this version because 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.pi 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 a building block toward having now a reusable function like print row am I doing all this like why are we over engineering 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 three by three grid a three by three 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 hmm 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 a moment that there is already a function called print Square that's going to be with 3 and height 3 as well 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 three by three 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 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 2 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 brick in row print brick and here is where comments and more generally pseudocode can really help explain to yourself and to others what your lines of code are doing on line eight I'm iterating from I equals zero on up to size so zero one two on line 11 I'm doing the exact same thing but using J from 0 1 2 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 one two three one two three one two three 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 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 backslash n where the cursor moves to the next line so if I now roll go back to my terminal window and run mario.pi I think I should get a three by three square and it doesn't quite look like a square on my screen because these hashes are a little taller than they are wide but it is in fact three by three but let me propose as we've always done here how we might tighten up this code further just for clarity's 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 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.pi 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 oh passing in size and let me propose that this print row function it simply taken 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 altogether 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 by which you can troubleshoot those same problems [Music] [Music] thank you all right this is cs50's Introduction to programming with python my name is David Malin 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 vs code on my computer here and in the terminal window I'm going to go ahead and run code of hello.pi that's going to of course open up a brand new tab for me hello.pi 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 ahead 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 my terminal window now and run python of hello.pi 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 errors on the screen but the Salient point is this bottom most thing here notice where it says syntax error 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 awry 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 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 close the quote and if I now go back down into my terminal window and rerun python of hello.pi now I'm saying hello to the world so the catch with 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 get-go 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 new file altogether I'm going to close hello.pi and I'm going to write code of say number dot Pi 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.pi after opening this new tab is I think I'm going to go ahead and print 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 int 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 dot Pi I hit enter and so far so good all is well I'm 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 and he 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 but uh what is an interface we got in a in a integrated IDE we can't code in an 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 dot Pi 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 zero seems to work my code still prints out that X is zero what might be another Corner case to consider well let me go ahead and try a negative number that 2 is pretty different in spirit from 50 negative one 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 cat 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 in 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 two is a bit of a mouthful and unfortunately in Python in a lot of programming languages the error messages are written for pretty comfortable programmers 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 which is this the default that 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 in integer or please don't type cat please don't type strings of course the user might still not oblige 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's literally says accept value error and notice it's important that I've capitalized the V and I've capitalized the E these 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 been dented 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 dot Pi 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 at X is not an integer I'm not seeing some scary error message that I have a user and I'm 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 ever the only type of ever 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 see 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 do use the accept block you need to know the type of error right like here you knew it was a value Adder 40 what if you can't anticipate this particular type of theater 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's sometimes times 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 is 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 y 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 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 L 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 of value error but I fear I've introduced a new mistake well let's see what is now incorrect let me go ahead and again run python of number.pi 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 cat 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 try block so good terminology scope refers to the portion of code in which a variable exists that too though isn't quite right in Python that would be true in CC plus plus and 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 Y is X somehow still not defined um yeah so is it because it's local variable meaning that like it doesn't Define outside of scope is like what people have mentioned it's it's asked it prompts the input in try right but outside of it is undefined so still good instincts and good terminology too there's this notion of local variables which tend to exist inside of functions for instance Global variables which can 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 lie 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 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 online 2 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 else now we've seen else before if you think back to our discussion of conditionals we saw if we saw L if we saw else 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 try accept feature of python 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 slides three and four to handle that value error however if you try and this code succeeds then there is no exception 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 else both for conditionals if L if L if L if else and we're also using else with these try 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 dot Pi 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 and 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 dot Pi 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 accept 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 else a moment ago we had code that looks like this whereby I was getting a name error python of number dot Pi enter typing in cat at 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 inputted 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-t 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 6 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 introduce finally the else statement that makes sure that these things are mutually exclusive I only execute the else if I tried and succeeded up above well let me propose that 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 user friendly 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 try accept 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 code 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 9 executes as I would hope so let me go ahead and try executing this version python of number dot Pi 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 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.pi 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 we really need to break can't we just print or what keeps us from just printing a good question so let me try that well let's see what happens if I do that let me move this print line at the end into my Loop here thereby shortening the program and in general that's been a good thing python of number dot Pi 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 hi uh can I use break our except else for example in another uh print print in the else you can use prints together with break or something like this 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 except else statement two 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 else if I wanted to I could actually do this I could get rid of my else 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 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 gonna 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 dot 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's 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 p 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 else 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 they 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 int 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 to print something on the screen like a side effect but is to hand back a value to hand you back a 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 t 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 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 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 compact 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 drive function uh when you're trying uh you take the input X and then return X good we can just return x a little higher up and let me correct folks as we go it's not a try function it would be a try 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 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 to you 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 silently ignore it like if you're talking in a room 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 reprompting the user so now the effect looks a little something like this python of number dot Pi 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 except else or pass okay yeah no 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 of the entire uh the entire function you know while true do this but I'm just kind of curious on the library 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 told the computer to do so so concretely what does this mean on line six here we're defining a function called get in 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 plus and Java that don't necessarily enforce 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 seven two 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 twelve 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 tried and indented below it is line nine that just means that what you should try is what's on my 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 istomeric here a 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 main 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 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 in 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 the 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 hard code so to speak that is type manually X all over the place let's make this function get into 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 Lee 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 Maine wants to use the get 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 into 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 variables 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 dot Pi 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 gotta 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 except options 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 exceptions and we'll see you next time [Music] foreign [Music] this is cs50's Introduction to programming with python my name is David Malin 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 in 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 dot Pi that someone else wrote probably long ago but that you have access to and in that random dot Pi file there's probably one or more functions that you yourself can use in order to do things 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 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 this 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 parentheses 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 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 dot Pi 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 module now suppose I want to flip a coin well I can do random dot 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 lists to iterate over students at Hogwarts let's go ahead now and let's 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 just want to simulate a 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 and 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 past functions I have to specify what module this function is in at least for now and so I do random dot choice to call the 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 dot Pi 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 an 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 alone 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 help 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 they're 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 function's name Choice into my current namespace into the scope of the file I'm working in what that means is that I now no 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 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 Muhammad 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 trays I choose so I'm gonna choose random dotted 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's 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 they're in well let me propose that we transition 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 end that's between A and B inclusive so if you were to pass in one for a and ten for B you would get back a number between 1 and 10 inclusive include including the one and including the 10 potentially each with a ten percent probability so how might I go about using a program like this well let me come back to my generate.pi file and why don't we go ahead and try generating a random number between one and ten you might do this frequently in the real world when you just want someone to pick a random number you tell them as much in the human response 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 1 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 a python of generate.pi and hit enter eight again nine again seven again ten 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 ten percent 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 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 as 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 they're in 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 dot 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 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 printed 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.pi and hit enter queen king Jack seemingly shot because that's not the order I defined earlier let's do it again queen king Jack 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 hmm not so good Jack queen king not so good this is someone 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 ten 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 course if you want to for example there is three there is a 33 percent 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 user-friendly 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 aspects of a data set that you might want to analyze so how might we use the statistics module in Python well we might first just take a look at its documentation like any other module in 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 envious code in my terminal window open up a new file called average dot pi 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 statistics dot 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 a hundred percent 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 two ants 190 and ins 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 in vs code Type in Python of average dot pi and hit enter and voila as you might expect my average is 95 percent 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 and Python and there's this feature generally known as command line 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 of just when you're executing it at the command line so up until now for instance recall that we've generally run python of something.pi for instance pythonofhello.pi 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 vs 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 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 that 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 sys module in Python there is a variable that just magically exists for you called ARG V 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 sys.org V this variable is a list which means that the first element is going to be the first word that you type the second element is going to be the second word that you typed in 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.pi let me go ahead and import CIS within that sys module is going to give me access to sys.org V 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 sys.rv bracket one and that's it I'm going to have a program here that says hello my name is followed by whatever is in sys.rv bracket one and notice cis.org V 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 dot Pi 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 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.pi 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 sys.rv even though it sounds certainly at first glance uh rather complicated here let's look up at sis.orgby I'm going to bracket one here so clearly sys.orgv bracket one is storing d-a-v-i-d 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 this 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.org V of zero what is probably insist.org V of zero the very first element actually in that list oh yeah I think uh it's like in C uh the name of program indeed it's indeed like in C in other languages 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 dot pi 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 sys.orgv 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 sys.org V let me go ahead and try this python name dot 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 uh oh 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 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 dot Pi it says hello my name is name.pi 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 to say okay we haven't got a parameter or something but if there is you 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 too 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 name.pi enter and too few arguments okay let me go ahead now and do python of name.pi 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 undo the exception handling I've added and why do I instead more modestly try to do this let me go ahead and introduce a conditional here if the length of cis.org V is less than 2 or equivalently equal to just 1 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 sys dot ARG V 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.pi and voila a completely different type of error this one a syntax error which we've seen in the past now a syntax error recall is mayakopa 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 it 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.pi 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.pi David Malin 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.pi 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 all together by just checking first is it too few is it too many or is it exactly what we want oh yeah 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 uh allow me to propose we come back to that support for multiple names but indeed we could do that and I should know too though we can support full names right now if I do this instead of typing in David space Malin which is problematic because again by definition of how ARG V 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 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 elif else or on accept before I want to ask you uh can we use multiple else in statement can you use multiple else's statements no else is the last catch-all statement that you can have you can have multiple l if statements in the middle but not multiple else's 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 sys 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 El lifts 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 else 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 there 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 else 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 sys.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.pi and I don't type any arguments I've got too few I think I'm going to see that I 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 too 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 too few arguments I'm going to use one other function that comes with the sys module I'm going to go ahead and call Sis dot 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 four 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 sys.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 an item at location one in sys.org V so let me go ahead now and run this python of name.pi enter too few arguments but I'm back at my prompt nothing more has happened let me run it again python of name.pi David Malin with no quotes enter too many arguments is now printed here finally python of name dot Pi just David enter hello my name is David so we have then insists two forms of functionality now we have access to this variable sys.orgv 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 out 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 to exit anyway so I'm using sys.exit now just to make sure that I exit earlier than otherwise um my question is about the CIS that are are V so is that capable of accepting or taking multiple elements at once let's say for example uh python name that by David Malin 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 you're you're your age is brought say at the sixth index can I say sys dot RV one and another one for six to access what I just want is that possible for assist 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 tag tags not just for David but for David for Carter for wrong 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 ARG in sis.org V 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 sys.org V 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 ARG 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 Arc 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 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 does look wrong so how could we get access to not all four elements of argv but just a slice of ARG V and this is actually a technical term in Python in 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 sys.org V 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.pi 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 bracket one we can also get subsets of the slices of the list by doing bracket something colon Something where each of those some things 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 sys.org V hype so I remember very early on uh when we were talking about only having two decimal places in uh in an float value um does this is is that in the same vein like um because we use the the colon point to f uh so that's is that the same thing then uh why would the F be included then in the point 2 f 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 keyboard 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 fstring 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 Pi Pi websites 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 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 set cow say is a package in Python on that allows you to have a cow say something on your screen if curious to read up on it its own documentation is on pipi.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 say now what's going on here pip is the command the package manager and I want you to install what package the package called cow say I'm going to go ahead and hit enter here and after a little bit of output it has successfully installed cow say 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 dot Pi because I want something to be said on the screen and in my new tab here I'm going to go ahead and import cow say which presumably is now installed I'm now going to import sys 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 sys.org V does equal to 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 Cow Say 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 CIS dot ARG V bracket one so long as then I type in my name David after the name of this program it should end up in sys.org V1 in which case this line five of codes 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 dot pi and type my name David and enter there is the program called cow say it literally has a cow say something on the screen and this is a throwback to a program from yesteryear that tended to come with a lot of systems this is otherwise known as ASCII 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 cow say 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 say.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 sys.org V equals equals two and only if it equals equals two do we do anything that's why we're not seeing anything here let me go ahead and cooperate now say dot Pi 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 third-party 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 my first question is the packages that you're calling um to uh use in the program are they the same as um let's say because if I'm doing Java um the same as calling a class or Java file in order to use its functions and my second question is what's the actual purpose of using command line arguments as you've used because it's not really the best way to 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 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 dot something dot 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 yes 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 command line 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 have we been running python of something dot Pi you could imagine not doing that you can 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.pi 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 hands down absolutely using command line arguments is a more Arcane 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 gui's and menus but the more comfortable yet 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 third-party 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 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 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 ecosystem 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.pi it turns out that Apple has its own API for their tune 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 colon slash itunes.apple.com search question mark entity equal song Ampersand limit equals one 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 and 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 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 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 contains all of the information in Apple's database on Weezer's song at least the first one because 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.pi 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 sys 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 cis.orgv does not equal 2 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 sys.rv 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 sys.rv 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 exactly the same as before https colon slash itunes.apple.com search question mark entity equals song Ampersand limit equals one 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 artist 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.orgv bracket one 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 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.pi 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 a Json response JavaScript object notation but python the requests 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 results 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 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 formatted 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 dot dump s for dump string and pass to that function that response.json return value so again I'm just introducing an 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 indented 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.pi 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 as 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 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 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.pi that doesn't just dump the response from the server 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 O equals response dot Json just a 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 results go ahead and print out that result track name and notice I have used exactly the same capitalization track name has a capital N results is all lower case 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 thereof I am then on line 10 just grabbing from that variable that contains the server's response 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 1 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.pi 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 break instead of system.exist exit good question but no break again is used to break out of things like Loops like we saw earlier sys.exit is used to break out of the whole program itself use break for Loops for now and use sys.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 can we change the results name you cannot you 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 third-party server other questions uh yes sir I have a question related to to Cow Say package so like uh yes so sort of what sort of uh ASCII Graphics uh is it capable of outputting the cow say 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 ASCII art uh is the all we had before there were emojis let alone gifs and jpegs and pings but it's what is immortalized in cow say 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 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 Pi Pi for others to use as well okay I'm going to go ahead and run code of sayings.pi to create a brand new file called sayings.pi which is going to be my own sayings module 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 a name parameter is input and that function is simply going to print out an F string that contains hello comma and then in curly braces 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 goodbye 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 braces 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 let's try it out python of sayings.pi 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 dot Pi but start fresh and rather than have the cow 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.pi I can say from sayings and it's inferred by python that I mean sayings.pi at least in this current directory but I specifically am going to import just one of the functions for now namely hello and now I can do something like this if if the user obliges by giving me two command line arguments which I can check by just checking the length of sys.r V I'm going to then go ahead and call this new hello function passing is its input assist.org V bracket 1 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 say dot pi 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 in 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 say dot Pi 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.pi 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 main main 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 underscore main underscore underscore 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 underscore 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.pi so Watch What Happens now with this additional conditional in sayings.pi if I run python of sayings.pi it's still works as before because name will be automatically set to underscore underscore main underscore underscore when I run this file using python of sayings.pi 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 line of code even though it will cause python to go find sayings.pi 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 main will not get called by definition of that name's value so let me go ahead and try this instead of running python of sayings.pi which is the module which contains that conditional main let me go ahead here on run python of say dot Pi which is the program here before me that Imports hello from sayings but because of that conditional it's not going to say it 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 say.pi 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] thank you foreign [Music] this is cs50's Introduction to programming with python my name is David Malin 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 habits 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 tests 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 squared or 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 dot 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 squared 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 so I could technically choose any name for this variable and I recall did this I returned n times 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.pi and hit enter what's X let's start with two all right x squared is four I think that's correct so let's run it again just for good measure python of calculator.pi let's type in 3 for X this time x squared is nine 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 an 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 underscore name underscore underscore equals equals quote unquote underscore underscore main underscore 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 and calculator.pi I've readied myself to call Main conditionally so that I can safely import one or more things from this file in another file well what should I that other file being 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 dot Pi 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 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 test underscore 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 x equals 2 and x equals 3 but every time I 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 mic 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 do I do this if the result of calling square of 2 does not equal 4 why don't we go ahead and print an error message because I know that in the real world 2 squared should equal 4 so if square of 2 does not equal 4 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 squared was not 4 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 3 does not equal 3 squared 9 then let's go ahead and print out that 3 squared was not 9. so I haven't done any more testing than I did earlier but I've baked those two tests x equals two and x equals 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 in our convention for doing that is the same as always in this function here in this file too let me Define Main and Main 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 underscore name underscore underscore equals equals quote unquote underscore underscore main underscore underscore 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 times n so a reasonable mistake to make perhaps arithmetically let me now go back to my test calculator which I'm not going to change but I am going to rerun it python of testcalculator.pi I'm going to cross my fingers here but for naught I'm going to see immediately that 3 squared was not 9. 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 nine and ten is fine because I'm not seeing that output but of course these two lines this test is failing because 3 squared is not 9 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 two plus two is four yeah I mean it's as simple as that I just got lucky that two plus two is the same thing as two times two 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 ten or Twenty 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.pi 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 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 2 should equal 4. or 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 nine 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 dot Pi crossing my fingers is 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 3 equals equals nine now unfortunately when you're using the assert keyword it's not terribly user friendly 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 fail 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 3 not equal to nine 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 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 in that I can at least catch this error but it's going to be perhaps a step backward in 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 as cholo 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 user-friendly that explains what actually failed 2 squared is uh was not four and let me go ahead similarly and try to assert that the square of 3 equals nine except if there's an assertion error there in which case I'm going to print out more user are friendly 3 squared was not 9. 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 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 testcalculator.pi crossing my fingers all right it still failed because I'm seeing output but we're back to at least user friendly 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 where 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 negative 2 equals equals 4 which should be the case mathematically and if not let me go ahead and change this to say negative 2 squared was not 4 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 of negative 3 which should equal 9 but if it doesn't let's go ahead and say that negative 3 squared 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 negative two I've tried negative three 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 interest in case two 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 except block let's assert that the square of zero should equal zero and if not I'll say something explanatory like zero squared was not zero now if I go ahead and run this python of test calculator dot pi and hit enter now I see multiple errors and this is interesting it's a bit of a clue because notice that sum but not all of these assertions are failing the one for two squared is apparently okay as we noted earlier recall that 2 squared 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 negative two and negative three because all of those tests caught this error the zero test did not notice because 0 squared is of course zero but zero plus zero is zero 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 accept 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 Pi test so Pi test is a third party program that you can download and 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 code yourself manually they do some of that automatically for you now this is a third party Library there's other libraries for unit tests so to speak that is testing units of your code some of them come with python itself we're proposing that we look at Pi test today because it's actually a little simpler than the unit testing Frameworks they 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 vs 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 which were accumulating to like 31 lines of code and let's see if we can distill the tests to their Essence using pi 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 2 should equal 4. I'm going to assert that the square of 3 should equal 9. I'm going to assert that the square of negative 2 should equal 4 and I'm going to insert that the square of negative 3 should equal 9 and lastly for now I'm going to assert that the square of 0 should equal 0. 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 not try and accept in 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 that's where indeed Pi test comes into play per the documentation for pi test which can itself be installed with Pip install Pi 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 Pi test is pretty user friendly as testing Frameworks go and it actually allows us to Dive Right In by just running Pi test on the code that we've written so if I go back to vs code here and look at my test calculator.pi 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 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 test underscore 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 well 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 four which is fine there's no red error message below that so that one's okay but this line of code here insert that square of 3 equals equals nine 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 nine 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 3 it turns out its return value is 6 and of course mathematically 6 does not equal equal nine 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.pi how in the world is line seven of my square function returning 6 instead of nine and at this point odds are the light bulb would go off above your head proverbly and you would see oh I'm using addition instead of multiplication but what pi 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 a 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 dot Pi crossing my fingers again and now it's green and I see just a DOT which indicates that my one and only test passed I'm good a hundred percent 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 instead of because we are taking input from the user what if the user is 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 cat 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 there could be one of those bugs and in fact there would be because if the user types in a string like cap 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 in 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 passed 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 to test uh code for the seats cs50 check so check 50 is similar in spirit check 50 is a tool that we cs50 wrote that is essentially doing something like Pi test for the evaluation of students code it is similar in spirit but think of check 50 as being an alternative to Pi test if you will but it works a little bit differently but same idea Pi 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 my question is instead of writing four times like s square of 2 is equal to 4 instead of that can be read if is it 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.pi it's indeed pretty manual I mean it took me a while to say and to type out those several lines and you can 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 tests 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 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 one two three four five separate tests and 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 3 equals equals nine 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 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 altogether 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 and let me test only negative 2 and negative 3. then down here let me do one more depth 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 attempted 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 testcalculator.pi 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 or 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 four that one's fine it's not erring 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 too why well when I pass in oh this is interesting here now negative 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 one line 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 a hundred percent 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 pi 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 tests really good question you could absolutely make separate files to test different types of things or if you don't have that many you 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 an example that allows me to put them into a folder and even run Pi 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 an exception called Assassin 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 set 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 Pi test this third-party library is handling the process of catching those exceptions automatically for me so as to give me this standard output so we started 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 and accept 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 so Pi test and you unit testing Frameworks like it just automate so much of that essentially Pi test ads 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 so uh when we enter -6 or minus five uh the square or square square root of that number comes up but when we put a 6.6 or 5.6 something like that integer then uh yeah light shows the error so what's happening there so uh if I'm deliberately testing integers right now in large part because I only want pow to operate on integers and that might be conveyed in Python's documentation or my own documentation for that function if you 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 past 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 python 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 testcalculator.pi and let me go and add a fourth test down here how about Define test underscore and I'll call this test stir 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 word for that rather we need this let me go to the top of this file and let me additionally import the pi test 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 pi test dot raises and then in parentheses 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 dot Pi 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 vs code to that very first program we wrote a few different versions of in hello.pi 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 paren 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 underscore main then and only then do I want to call Main so that's essential actually 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 Maine 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 dot Pi 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.pi the function Call To Low and how do I go about testing this well if I have a function like Define test argument like this well let me see this so if I were to find a function like Define test hello what could I do well I could call hello with quote-unquote say uh uh David and then check if it equals what hello comma David so with 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 dot Pi you're using the toe argument that you first declared 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.pi 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.pi typing in as my name d-a-v-i-d 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.pi 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 Pal function that explain 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 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 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 practice not not to have side effects 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's name is passed in is 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 testable why because these assert statements that we're using and we've seen thus 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.pi looks like this and hello is indeed returning a value in my test to low function I can test it exactly like this so let me go ahead and run Pi test of test hello.pi 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 other scenario what if I Pat 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 dot pi and that too passes entirely but there too suppose that I had made some mistakes 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 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.pi 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 about function inside the function can we test that too or recursion we we haven'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 assets or for the values absolutely you can absolutely use a loop to test multiple values in this case for in 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.pi 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 tests 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 test for our tests for our test 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 Pi test and other Frameworks support that Paradigm as well in fact let me go ahead and test hello.pi using a folder of tests with technically just one test but it'll be representative of having even more in that folder I'm going to go ahead and create a new folder called test using make dir 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 dot Pi 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 Pi 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 underscore underscore init underscore underscore dot Pi which has the effect even if this file is empty of telling 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 under underscore underscore in it underscore underscore 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 clue 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 Pi test not even on that specific file but on a whole folder of tests so if I run Pi test of test where the test is the name of that folder Pi test 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 a hundred percent 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 alright that's it for this week we'll see you next time [Music] thank you [Music] all right this is cs50's Introduction to programming with python my name is David Malin 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 i o 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 them from only using memory and variables and the like to actually writing code that saves 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 dot Pi 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 it 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.pi and hit enter type in my name like David of course I now see hello comma David so 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.pi 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 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 dot append name to that 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 altogether 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 an F string that says again hello bracket name close quotes all right let me go ahead and run this so python of names dot pi and let me go ahead and type in a few names this time how about Hermione 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 a laptop or desktop or Cloud to be able to save this information somehow instead and that's where file i o 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 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 programmatically 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 write 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 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 contents 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 a linking to that file dot write 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 Dot 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's 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.pi and enter let's type in a name I'll type in Hermione 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's Hermione well let's go ahead and run names.pi once more I'm going to go ahead and run python of names.pi 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're not appending them we should append the names since we are writing directly it is erasing the old content and it is replacing with the last uh 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 Vishal 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.txt 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 append 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.pi and enter I'll again start from scratch with Hermione because I'm creating the file new notice that if I now do code of names.txt enter we do see that Hermione is back so we've after removing the file it did get recreated even though I'm using append 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.pi 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 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 [Music] the English format is not correctly it's concatenating then it is it's it can it's well it appears to be concatenating but technically speaking it's just appending 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 appending 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 add a new line before we write your name good we want to add a new line ourselves so whereas print by default recall always outputs automatically a line ending of backslash n unless we override it with the named parameter called end write does not do that right takes you literally and if you say right Hermione that's it you're getting the H through the E if you say right Harry you get the H through the uh 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 close names.txt 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 backslash n at the end we could do this in different ways we could manually print just the new line or some other technique week but I'm going to go ahead and use my f strings as I'm in the habit of doing and just print to 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 dot Pi 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 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 long term 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'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 liked 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 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 find 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 with 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 4 is done executing so it doesn't change what has just happened 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.pi and let's add in Draco to the mix so now that we have all four of these names here how might we want to read them back well let me propose that we go into names.pi now or we could create another program altogether 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 on quote 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 yes 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 i o and 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 2 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 as 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 comma and then I'll print out the line itself alright so let me go to my terminal window run python of names.pi 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.pi it's saying hello to Hermione 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 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 we're fall 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 of 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 game 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 with statement at top and inside of this with statement I'm going to say this for line in file go ahead and print out quote unquote hello comma and then line Dot R strip 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 and 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 then 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.pi it's correct I'm seeing each of the names and each of the hellos 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 see 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 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 an 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.txt 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 names 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 F 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 three through five iterate over the file from top to bottom reading in each line one at a time stripping off the new line and adding just the student's 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.pi 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 pythonupnames.pi 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 where by 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 lowercase 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 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 Zeta air 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're one of them in descending order is there an extension for the 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 overriding the default of false let me now run python of names Dot pie 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 odds are if you have some problem odds are some programmer before you have had the same question other thoughts uh can we limit um and the second question can we find specific claim at 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 sys.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 this function like uh read all lines and it looks like it's uh like separate all the lines by this special character a backslash n but it looks like we don't need it a character and we we always trip it and 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 R 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 probably to separate one 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 or 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 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 it's a little 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 name 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 separate lay well let me go ahead and create a new program here called students.pi 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 quote 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 it as you would and if you were using a dictionary like using a key and value so ideally we would access it using it a key in value but at this point in the story all we have is this loose Loop is giving me one line of text that is the 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 Hermione 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.pi 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 R 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 strip 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 line of it as being a row and each of the values they're in 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 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 Hermione 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 and the other and so forth so bracket zero is the first element because 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.pi enter and we see Hermione is in Gryffindor Harry's and 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 edit any line of code anytime we want or uh the only option that we have is to append uh the lines or let's say if we want to let's say change headies 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 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 Slytherin 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 zero 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.pi 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're 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 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 dot 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 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 students like this well let me go ahead and run python of students.pi and hit enter now and I think we'll see indeed Draco is now first Harry a second Hermione 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 well 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 on line 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 in 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 could create an empty list with square brackets you can create an empty dictionary with curly braces so give me an empty diction 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 students in students and let me very Simply Now say print the following fstring the current student with this name uh is in this current students 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 uh because you have double quotes in that in that line 12 and so you have to tell 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 2 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 two 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-empty 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.pi 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 not obvious how you would sort a dictionary inside of a list so ideally what do we want to do if at the moment we hit line 9 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 ran 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 position National 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 functions 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 sort it 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 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.pi and hit enter I now have a sorted list of output why because 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.pi and hit enter now it's reverse now it's Ron then Hermione 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.pi 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's 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 do 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 construct construct those sentences in advance like I rather hackishly did the first time all right that was a lot let me pause here to see if there are questions so when when we're starting the files do we every time should we use the loops or like uh like a dictionary or or any kind of list can be sort by just sorting not uh 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's equal to the return value of the function uh can it be equal to uh just uh a variable or a value it well yes it should equal a value so I'm speci 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 automatically 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 the nested dictionaries what is the difference between nested dictionaries and the 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 and 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 us 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.pi 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 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 will 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 parentheses I'm passing in an only by its name so that the sorted function can call that get name function for me now it 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 altogether 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 an a Lambda function which is an anonymous 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 is 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 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 pi 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.pi 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 have a 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 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 followed 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 Death 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 Ron grew up in the borough Harry grew up in number four privet drive and according to the internet no one knows where Hermione 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.pi here and let me propose that I just changed 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 changed 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.pi 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 instruments.csv you have three values there's a line that you have three valleys and incidents yeah I spent a lot of time trying to figure out where 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 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 a little more 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 bar 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.pi 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 the 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 and or 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 propose 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 with 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 CSV dot reader 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 commas and 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 Rose 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 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 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 for 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.pi and hit enter and now we see successfully sorted no less that Draco is from malform Manor Harry is from number four comma privet drive and Ron is from the borough 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 ourself and reading each of those commas and splitting so my questions related to Something 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 case if you want you could you could write some stuff to the file but then at the same time you could have another function that reads through the phone that's 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 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 piecemeal changes which is good if though the file is massive and it would just be very expensive time wise to change the whole thing other questions on this CSV reader is possible to write 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 choose himself IP 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 segue 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 all odds are you've noticed that the first row very frequently is a little different it actually is bold face sometimes or it actually contains the names of those columns the names of those attributes below and we can do this here and 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 someone'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.pi 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 addict 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 should behave pretty much the same python of students.pi 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 to 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 borough then by Ron and then lastly Malfoy 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 touch it at all I'm going to rerun python of students.pi 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 a 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 Gryffindor for Harry Gryffindor for Ron and Slytherin 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.pi and I don't change the code at all and runs python of students.pi 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 named the second column is 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 csv2 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 re-add 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.pi 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 dot writer and that writer 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 dot right row and I'm going to pass into right 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.pi hit enter and what's your name well let me go ahead and type in Harry as my name and number four comma privet 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.pi let me go ahead and input this time Ron and his home as the borough let's go back to students.csv to see what it looks like now we see Ron comma the burrow has been added automatically to the file and let's do one more python of students.pi 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's name it also handled the escaping so to speak of any strings that themselves contain a comma like Harry's own home well it turns out there's yet another way we 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.pi and this time instead of using CSV writer I'm going to go ahead and use csv.dictriter 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 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 red even if those orderings change let me go ahead and pass in field names which is a second argument to dictwriter 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 columns 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.pi this time I'll type in Harry's name again I'll again type in number four comma privet Drive enter let's now go back to students.csv and voila parries 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 India and your specifics suppressive fake situation for me to use a single quotation or double quotation because after the print we use a single quotation to represent the key of the dictionary but after the reading or writing we use the double quotation it's 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 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 it when you're reading could couldn't you just call the row in the previous version of the of the students uh dot Pi 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 appending 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 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 involved that might not be aligned with your code's expectations things then yes can break 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 uh 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 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 a lot Instagram you can animate them as well and so what I thought we'd do is leave behind behind text files for now and Tackle one more demonstration this time focusing on this particular library and image files instead so let me propose that we go over here to vs code and create a program ultimately that creates an animated gif these things are everywhere nowadays in the form of memes and animations and stickers and the like in 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 cost team here number one so suppose here that this is a costume or really just a static image here costume1.jif 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 costume2.jif 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 two to create our own animated gif that after this you could text to a friend or message them 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.pi and create our very own program that's going to take as input to or even more image file 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.pi 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 sys so that we ultimately have access to sys.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 sis.org V I'm going to go ahead and create a new image variable set it equal to this image dot open function passing in ARG now what is this doing I proposing that eventually I want to be able to run python of costumes.pi and then as command line arguments specify costume1.jif space costume two dot shift 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 sys.org V 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 append 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 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.jif 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 I'm going to then append to this first image the image is zero 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 milliseconds for each of these frames and I want this to Loop forever and if you specify Loop equals zero that is time 0 it means it's just not going to Loop a finite number of times but an infinite number of times instead and I need to do one other thing recall that sys.org V contains not just the words I typed after my program's name but what else does sys.org v contain if you think back to our discussion of command line arguments what else is insist.org V besides the words I'm about to type like costume 1.jif and costume two yeah so we'll actually get in that their original name of the program we want to run the costume set python indeed we'll get the original name of the program costumes.pi in this case which is not a gif obviously so remember that using slices in Python we can do this if sys.orgby 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 it 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.pi and now I'm going to specify the two images that I want to animate so costume one dot GIF and costume2.gif what is the code now going to do well to recap we're using the sys 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 line seven through nine 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 onto 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 dot Jif to open up in vs 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 i o 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 it for now we'll see you next time [Music] [Music] thank you all right this is cs50's Introduction to programming with python my name is David Malin and this is our week on regular Expressions so a regular expression otherwise known as a regex 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 completely different so using regular Expressions we're going to have the Newfound 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 VSCO code here and let me create a file called validate.pi 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.pi 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 the 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 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 it 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 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 get 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.pi and I'm going to go ahead and give it my email address mailon harvard.edu enter and indeed it's valid looks valid is valid but of course this program's 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 well please just you can type just to science science and visit and still be able to still be violated according to your program but the same exactly we've set a very low bar here in fact if I go ahead and rerun Python and validate.pi and I'll just type been 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 mailing at harvard.edu so let's check for that dot as well 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 in email as well so I'm asking now two questions I have two Boolean Expressions if at an email and I'm ending 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 validate.pi Malin 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 I do this like this 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 email dot split 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 implies we'll split one stir into multiple ones if you give it a character or more to split on so this oh 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 responses 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 username 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 bid 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 parentheses there parentheses here so just to be clear it's really two Boolean Expressions that we're ending together not one longer english-like sentence now if I go ahead and run this python of uh validate.pi enter I'll do my own email address again mailing harbor.edu and that's valid and it looks like I could tolerate something like this if I do mail-in 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 dot 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 U.S University for instance whose email address tends to end with DOT edu I can be a little more precise and you might recall this function already instead of just saying is there a dots 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 DOT edu let me go ahead and run Python and validate.pi and just to make sure I haven't made things even worse let me at least test 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 Malin 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.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 mailen.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 iterate on this program and we could add some more Boolean Expressions we could maybe use some other python methods for checking more precisely is there 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 succinctly 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 and 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 argument 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 cup 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 vs 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 in first and fall 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 white 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 dot 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 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 A validate.pi and enter I'll type 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 at sign then something to the right and that something to the right should end with DOT edu but should also have something before the dot edu like Harvard or Yale or any other school in the U.S 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 are 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 re.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 three hundred 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 0 of this character or one but that's all I'll expect and then lastly there's going to be a way 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 three hundred 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 Malin 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 person's 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 dot 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.pi 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 Malin 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 Malin at with no domain now considered valid what's my mistake here by having used dot star at dot Star as my regular expression or regex because you're using the star instead of the plus sign exactly the star again means zero or more repetitions so re.search is perfectly happy to accept nothing after the equal 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 dot star to dot plus and let me change the ending from dot star to dot plus so that now when I run my code here let me go ahead and run python validate.pi 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 can 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 start 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 a A or AAA or AAA 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 you 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 dot star at dot star 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 re.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 is reading my email address mailin 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 mailing 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 r d dot e d u and that's it and then the computer is 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 user's input it is indeed a valid email address if by some chance the machine somehow ended up stuck in that first date which does not have double circles and it 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 dot Plus on both the left and the the right recall that ari.search is going to use one of these State machines in order to decide from left to right whether or not to accept the user's input like Malin harvard.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 looked 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 the dot to indicate that we can consume any one character like the m in Malin 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 regex 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 d u 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 to 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 our username and also something after the username like a domain name but minimally required that the string ends with DOT edu 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 DOT 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 dot Plus at dot plus dot edu what could go wrong with this version uh the dot is in a DOT means something else in this context where it means three or multiplications of a character which is rightly interpreted differently exactly even though I mean for it to mean literally.edu a period and then dot edu unfortunately in the world of regular Expressions dot means any character which means that this string could technically end in a e d u or b e d u or c e d u 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 Malin harvard.edu and as always this does in fact work but Watch What Happens here let me go ahead and do Malin at Harvard and then mailing 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 dot edu literally any instinct thinks 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 you can use the Escape character the backslash indeed the so-called Escape character which we've seen before outside of the context of regular Expressions when we talked about new lines backslash n 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 backslash n was a way to escape and 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 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 backslash n which even though we as the programmer might type two characters backslash in 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 and 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 spirits 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 backslash 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 accidentally 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 or validate run python of validate.pi and then I'll type in my email address correctly mailing harvard.edu and that's fortunately still valid Let Me Clear My screen and run it one more time pythonvalidate.pi and this time let's mistype it as Malin at Harvard question mark edu whereby 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 DOT edu explicitly um what happens a good question and you kind of called me out here well when in doubt let's try let me go ahead and do pythonvalidate.pi mailin at at harvard.edu which also 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 uh curly brackets M instead of backslash 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 things 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 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 user's input into your Google form so in fact after today you can start avoiding the specific drop downs 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 vs code itself if you go and find or do a find and replace in vs code you can of course just type in words like you could into my 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 DOT 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 Malin harvard.edu but what if I type in a sentence like my email address is mailenharvard.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.edu 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 regular expression is not so precise as to say the pattern must start with the username and end with the dot edu 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 something else with a typographical 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 pay 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 represent 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 is 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 shows many years ago so let me go back to vs 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 mailing harbor.edu enter sorry a 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 too 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 Dot edu and then the dollar sign but that is like uh one of the regular expression right it normally is but this backslash that I deliberately put before this period here is an escape character it is a way of telling our e.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 ourselves 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 know that 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 mailing harvard.edu dollar sign which is obviously not correct too so backslashes just allow you to tell the computer to not treat those symbols specially likes meaning something special but to treat them literally instead how about one other question here on regular expressions to make it one plus then you said one was to make it one with nothing sure rewind in time I think what you're referring to is one of our earlier versions that initially looked like this which just meant Zero or more characters than an at sign then zero or more other characters we then evolved that to be this dot Plus on both sides which means one or more characters on the left than 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 dot dot star or you can just use the handier syntax of dot 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 dot 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 y 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 and validate.pi mailing at harvard.edu still works as expected but if I also run python to validate.pi and incorrectly do Malin at harvard.edu to you that should be invalid but it's considered valid instead so 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 carrot symbol which unfortunately in this context means something completely different from match the start of the string but this would be the complement 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 F's 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 take 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 closed 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 send text 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 except 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 e d u so now let me go ahead and do this again let me rerun python to validate.pi and test my own email address to make sure I've not made things worse and we're good now let me go ahead and clear my screen and run Python and validate.pi again and do Malin at at 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 in at sign one or more time is 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 b c d 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 up vs code and let me delete the current form of a regular expression and go back to where we began which was just dot star at and Dot 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 dot 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 the sets of characters or complementing that's set so can you use that same syntax to say that you don't want a certain character throughout the whole string you could it's going to be uh you could absolutely use the same character to exclude um you could absolutely use this 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 thing a good question what happens if the user types in edu at the beginning of the screen well let me go back to vs 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 dot 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 by running the program let me type in just literally.edu that doesn't work but but but I could do this dot edu.edu that too is invalid but let me do this dot edu at something.edu that 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 about one more question on this regular expression and these complementing of sets can we use uh another domain name the 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 dot edu which is very U.S Centric but this would absolutely work exactly the same for any top level domain all right let me go and head now and propose that we improve this regular expression further because if I pull it up again in 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 too 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 science 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 and 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 gonna 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 through z 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 no you don't need to type in all 10 decimal digits you can just say 0 through 9 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 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 pythonvalidate.pi 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 David underscore Malin harvard.edu enter but that too is going to be valid but if I do something completely wrong again like Malin at at 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 dot 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 reg 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 built-in 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 can use and in fact I can go ahead and get rid of this entire set a through z lowercase A through Z uppercase zero through nine and an underscore and just replace it with a single backslash W backslash W 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 backslash 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 this carrot on the left means start matching at the beginning of the string backslash w 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 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 backslash D for any decimal digit decimal digit meaning zero through nine commonly done here too is if you want to do the opposite of that the complement so to speak you can do backslash capital D which is anything that's not a decimal digit so it might be letters and punctuation and other symbols as well meanwhile backslash s means white space characters like a single hit of the space or maybe hitting tab on the keyboard that's white space backslash capital S is the opposite or complement of that anything that's not a white space character backslash W 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 backslash capital W to give you everything but a word character again these are just common patterns that so many people were presumably using in yesteryear 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 backslash w to represent my word character uh so I don't 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 dot edu or.com you could do this you could introduce parentheses and then you can or those together I could say Com 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 combine ideas into one phrase and do this thing or the other and there's other syntax as well that we'll soon see other questions on these regular expressions and this syntax here but if we put spaces in the expression sure so if you want spaces in there you can't use backslash W 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 square brackets and you could say A through Z or a through z or zero through nine 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 backslash W but I could combine it as follows I could say give me a backslash W or a backslash s because recall that backslash s is white 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 backslash W um include a DOT uh because no no 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 and so um I don't think our current version uh 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 in other English words when I typed out my email address as mailing at harvard.edu was because we were using initially dot star or dot 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 zero through nine and underscore did we finally get to the point where we would reject white space and in fact I can run this here let me go into the current version of my code in vs code which is using again the backslash W's for word characters let me run pythonvalidate.pi and incorrectly type in something like my email address is mailenharvard.edu period which has spaces to the left of my username and that is now invalid because space is not a word character your go 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 backslash W 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 backslash W technically does handle lowercase letters and uppercase because it's the exact same thing as that set from before which had a little a through little Z and big a through big Z but watch this let me go ahead in my current form run pythonvalidate.pi and just because my caps lock key is down mailin at harvard.edu shouting my email address it's going to be okay in terms of the mailing it's going to be okay in terms of the Harvard because those are matching the backslash W 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 backslash W yeah so you are asking for the domain.edu in lowercase and you're typing it in 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 lower case and I could put onto the end of my first line dot 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 insofar as I'm currently only passing into 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 lowercase 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 dot multi-line for just that or re.all whereby you can 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 r e dot uh ignore case let me now rerun the program without clearing my screen pythonvalidate.pi let me type in again in all caps effectively shouting mailing 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 to here is fine and why might I do this approach rather than call Dot 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 cases sensitively without actually changing the value of that variable itself are any final questions now on this validation of email addresses so the pattern is a string right uh can we use an F string you can you guess 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 backstage 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 perf 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 validate.pi and this time let me type in not mailing at harvard.edu which I use primarily but another email address of mine mailing at cs50.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 malinet cs50.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 through 9 and underscore so I'm gonna 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 mailing at something.cs50.harbor.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 modified 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 vs 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 sub domains I could say well let's allow for other word 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 pythonvalidate.pi will work for malinet cs50.harvard.edu enter unfortunately does anyone see where this is going let me rerun pythonvalidate.pi and type in as I keep doing Mainland harvard.edu which up until now has kept working despite all of my changes but now oh 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 your email addresses of the form username at domain.tld or username at subdomain.domain.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 we are using the Stray bar as a optional make the option 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 parentheses but I think there's actually an even easier way way 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 effectively 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 and validate.pi let me run Malin at cs50.harbor.edu enter that's still valid but to be clear if I rerun it again for mailing at harvard.edu that is still invalid but not if I go in here and say after the parentheses which now is one logical you unit it's one big group of ideas together I add a single question mark there this will now tell our e.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 Malin at cs50.harbor.edu so that the subdomain's there that works as before let me clear my screen and run it again pythonvalidate.pi with Malin 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 used not just the question mark But the parentheses as well okay yeah you said he 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 with question mark there's only one repetition allowed 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 sub domain within the domain name why well this part to the right is the same as always backslash W plus means something like Harvard or Yale backslash.edu means literally.edu so the new part is this in parentheses I have another set of backslash W plus backslash dot now but it's all in parentheses I'm now having a question mark right after that which means that whole thing in parentheses either can be there or it can't be there it's either of those that are acceptable so a question mark effectively makes 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 sub domain like cs50 and the additional dot to be what's there or not there how about one other question on regex 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 backslash W 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 zero through nine 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 backslash period and now I technically don't even need the upper case 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 note 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 our solution here instead this is where purse 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 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 expression still to validate things that aren't email addresses but there 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 re library for regular Expressions among them is this function here re dot 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 regex if you want to match from the start of a string re dot 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 two 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 action code whereby we solve a different problem in spirit rather than just validate the user'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.pi and let's go ahead and create a new program altogether called format.pi 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 dot pi 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 Malin but some users might be in the habit for whatever reason of typing their name backwards if you will with a comma such as mailen 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 Malin and there's no commas or backwardsness to it so let's go ahead and do something familiar let's go ahead 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 white 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.pi let me behave and type in my name as I normally would David spacemailin 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 Malin comma David and hit enter alright well this now is 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 Malin 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 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 U.S so let's do this it could be a little fragile but let's 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 comma but the space after assuming the human typed into space after their name and let me go ahead and store the result of that splitting of malen 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 addict 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.pi and hit enter I'm going to type in David space mailing as before and I think we're still good but I'm also going to go ahead and do this python of format.pi malen 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 attack the in their name comma and then sign them oh and then something else yeah so let me let me try this for instance um let me go ahead and run a program and uh I am the only David Malin 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 mail-in 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 base optional well I could use my newfound 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 space is thereafter 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 dot search and I'm going to search for a pattern that I think will be la last comma first so let me use my newfound regular expression syntax and represent a pattern for something like Malin comma space David how can I do this well inside of my quotes for re.search I'm going to have something so dot plus sorry I'm going to have something so dot plus then I'm going to have a comma then I'm going to have a space then I'm going to have something dot 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 than 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.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 dot plus here and the dot plus here so I've deliberately surrounded in 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 up another Plus or 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 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 surrounded 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 assign 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.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.pi and do mail-in comma 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 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 y 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 Malin 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 fstring again first and then last done and let me we're finding 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 dot group 2 first plus a space plus matches dot 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 zero and one really good question capturing 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 five space government white space how we check um true or Foundation before I answer directly let me just run this and make sure I've not broken anything further let me run python to format.pi let me type in David spacemailin the right way let me run it once more let me type it mail and 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 Malin 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 Malin comma space David or Malin comma David so let's try again before this did not work let's do Malin 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 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 a one I could use a star here so space star and now if I run this once more with Malin comma 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 in C or C plus plus 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 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 encoding 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 walrus 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 kinda 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 a format that's pi and type Malin comma 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 user's input by checking against a pattern whether it matches or not and if it does match we kind of reorganize some of the user's 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.pi and create a new file called twitter.pi 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 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 nuns for a better experience perhaps well let me go ahead and do this with twitter.pi let me first go ahead and prompt the user here for a value for a variable that I'll call 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 white space 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 user's address is the following let me print out what they type in and let me clear my screen and run python of twitter.pi I'm going to go ahead and type in for instance https colon slash slash twitter.com David J malen 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 uh we just ignore what's before the username and then just extract the username perfect yeah I mean it is as 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 slash 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 dot 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 it 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 Ivan 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 colon slash slash 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.pi enter URL here we go https colon slash slash twitter.com [Music] David J Malin enter okay now we've made some progress done for the day right well what is sub-optimal 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 like it's a few ideas actually well first of all uh if the if we don't specify https it's all broken secondly if we have sliced at the end it also will be broken if we if we have like a question mark or something after question mark it also won't work so let us know 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 type twitter.com David J Malin 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 slash 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 my username is https colon slash twitter.com David J Malin enter well that too just just didn't really work it got rid of the you 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 my username is https colon slash twitter.com David J malen a moment ago it did remove the URL and left only the David J Malin 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 line 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 up for now among them are those same flags and also account like how many times do you want to do find and replace do you want it to do all 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 colon slash slash twitter.com 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 Place function I want to replace it with nothing just get rid of it all together but what 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 Subs 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.pi and here we go https colon slash slash twitter.com David J Malin 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 prefix is Paul 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 taking 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 there could be like less than two slashes okay so it could be HTTP and I think that was mentioned too in terms of protocol they're slashes that I'm not I'm not gonna 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 dog without a backslash meaning any character is of a new one yeah exactly it's not it means any character so I could type in something like Twitter uh question mark Com or Twitter anything com and that would actually be tolerated it's not really that bad because 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 we 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 in question mark behind the S perfect just use a question mark right 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 verbose 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 habits 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 but it will work if you go to a browser I could do this www dot uh wait I want a backslash 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 square 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 www.twitt ER 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 slash slash 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 as 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 dot what if we use 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 dot or nothing and just leave that in the parentheses 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 fault 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 um inside we have another product that says to deal 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 it is 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 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.pi doesn't even type a Twitter URL what if they do something like https colon www.google.com 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 back-end system we're only saving into our database or a CSV file the use 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 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 URL of the string https question mark to make the S optional colon slash slash then I'm going to make my www 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 Malin 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 K so re.ignorecase applying that same lesson learned from before re.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 of characters now ari.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 dot 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 is the second argument for this regular expression this pattern I have surrounded the dot 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.pi and type in HTTPS colon 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.pi https colon slash slash twitter.com davidjmalen 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 dot 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 colon slash let's add it www.twitter.com David J malen all right enter ho ho ho ho what is going on we have to save group I have to say group two well wait all right because we had the the sub domain 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 lets you run this python of twitter.pi https colon slash www.twitter let's do this uh twitter.com David J Malin 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 our new friend it's hard not to like if we like our old friend The Walrus uh operator let's go ahead and add this just to tighten things up let me go back to BS 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 dot 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 dot with parentheses at least as I've written my regex 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 ternary operators doing an if else all in one 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.pi I'll again run here https colon twitter.com davidjmalen 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 dictionary to to sort the.com kind of thing if because we have core UK and that kind of sorry 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 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.com and the dot org and Dot edu and so forth the short answer is there's many different solutions here if I wanted to be stringent about.com and suppose that Twitter probably owns multiple domain names even though they tend to use just this one suppose they have something like dot org as well you could use more parentheses here and do something like this Com or org I'd probably want to go 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 dot group one now equals equals com 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 regex if it's in fact what you expect for now though we kept things simple we focused only on the.com 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 checked the documentation for Twitter and Twitter only supports letters of the alphabet A through Z numbers zero through nine 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 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.pi one final time typing in HTTPS colon slash slash twitter.com David J malen maybe with maybe without a trailing slash but hold 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 Malin 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.split 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.find all which can allow you to search for multiple copies of the same pattern in different places in a string so 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 newfound 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] foreign [Music] this is cs50's Introduction to programming with python my name is David Malin and this is our week on object oriented 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 this surface thereof today we focus on another Paradigm and this one in more detail namely object oriented programming and now while some of you might have prior programming experience and have learned languages like Java which are by Design fundamentally object oriented python indeed allows you a bit of flexibility when it comes to how you solve problems with code but it turns out oop object-oriented 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 passed so let's go ahead and do this let's start by writing a program very procedurally by opening up vs code here I'm going to go ahead and create a program called student.pi and in this program I want to do something relatively simple initially 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.pi 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 going to 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 student and Dot Pi 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.pi 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 by their names going to be to get the user's name and to get their users 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 underscore 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 eight if I'm immediately going to return that same name variable on line 9. 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 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 they 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.pi 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 had 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 justifying 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 this Student's name by prompting them with input as before and it's going to get the student's house by also prompting them as before and then now hmm 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 minimally like to return both of those I believe that we can return a dictionary include the name and the house yeah so we absolutely could return a dictionary addict object in Python whereby maybe one key is name one key is house and the values thereof are exactly the values of these variables so 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 written 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 around 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 returning a dictionary and putting multiple Keys therein 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 programs 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 is 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 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 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.pi 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 tuple a tuple 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 tuple and 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 9 you're actually returning one value which is a tuple inside of that Tuple now are two values so it's similar in spirit to returning one list with two things here I'm returning one Tuple 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 tuple but there's more explicit syntax that we can use instead I can actually more verbosely put explicit parentheses around the values of this Tuple 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 tuple 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 tuple 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 zero 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 Tuple let me go ahead and clear my terminal window again run python of student.pi 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 tuple and indexing into it in this way I guess that's like a actual use case where you would use a tuple 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 Tuple is just another way where you can increase the probability of correctness by just not letting anyone yourself included change the contents they're in 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 ahead and run this program once more as is pythonofstudent.pi let me go ahead and type in for instance how about padma's name and I'm going to go ahead and say that Padma is 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 inputted 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 students 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 Tuple 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 for uh at 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 type in Padma Gryffindor but in the books it was Padma from Ravenclaw all right let me go ahead and go down to my terminal window clear my terminal and do python of student.pi 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 student.pi on Padma and I'll put her2 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 I'm using a data type wherein there's an error and what is that error well Tuple object does not support item assignment it's a little arcanely Express that is that's not really very user friendly but if you think about what those words mean Tuple object does not support item assign 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 0 or 1 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 tuple 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.pi 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 Ravenclaw as in the books instead any questions now on tuples versus lists or this idea of immutability versus mutability it can be used a nested tackle in Python like a nested list 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 tuple 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 Tuple with two elements but yes you could absolutely do that too other questions on tuples versus lists okay for example um when I see this websocket um is it many use 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 tuple however somewhat confusingly both lists and tuples 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 made 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 in 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 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 in return students so now I am literally returning one thing still but this time it's a dict rather than a tuple 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 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 instead 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 button your your audio is 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.pi 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 it's 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.pi 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's 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 ten 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 names like name and house in this case but but let me tighten this up further and 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 lowercase 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 way was a little more readable and that's totally fine to create variables if they improve the readability of 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 case 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 like you can lists how do you do that it's 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 0 and 1 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 student dot Pi we'll again do Harry from Gryffindor and I think all is 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 tuples 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 so what if a combination of lists is there in a tuple so is the list like we can change the list because Tuple are immutable but listen 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 saying 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 house from the user you could imagine wanting longer term to collect even more information like the students Patronus 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 list or a dictionary but that's pretty reasonable right you can imagine just us 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 terminology is a class A Class is kind of like a blueprint for pieces of data object 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 of object oriented programming to be able to create your own objects in this way and in the case of python in 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 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 vs code let's use this new keyword and let me propose that we create a class called students 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 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 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 in spirit use of a DOT that allows you to get at something inside of something else so student dot 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 dot 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 object-oriented 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 it 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 dot name and over here I'm going to change it to be student dot 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.i 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 object oriented 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 R 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 plaster the mold when you actually use that mole 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 tuple 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 classes 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 or 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 presented them here in vs 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 on line 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 finding 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 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 is 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 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 Unity to customize this classes objects that is to say this underscore underscore 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 init 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 a 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 object oriented 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 there 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 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 closed parenthesis with arguments inside side suggests that there's a function somewhere in the world that has been defined with death 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 init 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 clear 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 and 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-secretely 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 itself 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 is 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 and what is the difference between the init method and default Constructor a good question so in other languages if you program before for instance Java there are expunctions 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 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 dot 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 a problem because I'm trying to implement a student sing regular so it doesn't really make sense to have multiple first names maybe a nickname maybe a last name so we could add those two 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 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 Vari 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 see do the same thing with the dictionary so I have 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 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.pi 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 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 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 object oriented 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 pythonically 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 sys.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 function 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 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-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 no no there is no object there is an object it's up 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 long 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 the 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 Slytherin quote unquote then with my colon let's 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 scroll back down to my terminal window and clear it let me run python of student.pi 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.pi and type Terry as the name but I this time typed in number four privet 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 raise 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 classes and in it and now this ability to raise exceptions when something goes wrong inside of the initialization so what if the 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 taking 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 him for their whole name so type in David Malin enter or David J Malin 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 or 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 my main code as needed absolutely a really good question you could imagine wanting to use this student class not just in student.pi 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 what we see that we've actually been using classes you and I before in third party libraries 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 egotistical and say I want to raise Eric error 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 for 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 and 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 a name and house but you could make things optional and yes 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 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.pi again let me type in Harry let me type in Gryffindor and voila Harry whoa okay main student object at ox102 733e80 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 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 ox102 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 the default way of describing via print what this thing 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 init underscore underscore But continuing that same pattern underscore underscore 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 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 vs code let me propose that I go in and Define not just underscore underscore in it but let me Define a second function in this class here as follows def underscore underscore stir underscore underscore they're r d two even though the font in vs code is putting the two underscores so close it just looks like a longer underscore there are indeed two there on the left and the right just like for init 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.pi 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 stir 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 underscore stir underscore underscore 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 from self.house so there's nothing new in what I've just done it's just an F string and F on the beginning two double quotes a couple of pairs of curly braces but because automatically this stir method gets passed 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 now if I run python of student.pi 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 dracos from Slytherin now it's customized to the specific object that we're trying to print questions on this function here this Dunder stir method is there anything else that the under underscore underscore stir method can do um the other question is what's the difference between stir and wrapper 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 underscore underscore repr underscore underscore 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 underscore stir underscore underscore is generally meant for users uh the users of the program and it's meant to be even more user friendly 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 special methods like double underscore in it and double underscore stir like let's create our own methods because therein 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 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 Patronus and I'm not going to worry uh for now on validating the Patronus from an official list of valid patronuses or patroni I'm instead going to go ahead and just blindly assign it to self.patronus equals Patronus 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 patronuses to a specific list of them here let me go ahead now and prompt the user for this Patronus as by in my get student method get student function defining a variable called Patronus or anything else prompting the user for input for their Patronus 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 student.pi I'll type in Harry I'll type in Gryffindor and it turns out his Patronus 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 a double underscore in it 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 patronuses 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 uses 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 Harry and Hermione 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 Charmed 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 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 Patronus all right how to implement this well inside of the charm method let's go ahead and match on self.patronus which is the instance variable containing a string that represents each student's Patronus 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 for Ron rather than Hermione 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 Patronus recognized as my cover someone like Draco let's go ahead and use a default case using the underscores as in the past and let's go ahead and return for this oh what should happen if someone doesn't have a Patronus 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 Patronus 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.pi and enter name let's start with Harry he lives in Gryffindor Patronus is a stag and let's see expecto patronum and of course we see the Stag Emoji what about someone Mike Draco who at least in the books doesn't have a known Patronus well let's go ahead and clear my terminal window rerun python of student.pi and this time let's type in Draco for name Slytherin for house and Patronus is unknown so I'm just going to go ahead and hit enter and now expecto patronum and just kind of sizzles instead questions now on what I've done by implementing this charm method can be 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 aligned 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 dot 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 you know parentheses you uh you put yourself 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 stir method and this new Char 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 hairy 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 Patronus 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 so I just wanted to ask that you have put the emojis in double quotes So does it take the Emojis as the form of strings or something else yes if uh 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 Patronus 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 Patronus 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 Patronus down here so it's essentially undo all of the fun charms 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 Patronus we're validating name up here we're validating house down here and then we're assigning name and house respectively to two in distance variables called name and house also but we used self to get access to the current object to store those values they're in 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 student.pi I'll type in Harry I'll type in Gryffindor enter okay we're back in business gone are the charms and patronuses 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 dot 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 students 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 gonna you're gonna require me to type in Harry and Gryffindor I'm going to go ahead and type in student dot house equals quote unquote number four privet 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 clear my terminal window and run python of student.pi 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 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 for 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 too 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 decorators 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 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 self dot 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 call it 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 I'm going to say sell uh rather I'm going to do self dot 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've had 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 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 error checking there so if house is not in the following list of Gryffindor or Hufflepuff or Slither or Ravenclaw or Slytherin just as before let's go ahead and raise a value error just to signify that 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.house to 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 dot house equals what's about to happen magically is python will not just let the programmer access student.house 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 know to do that well if it sees that on the left hand side there is self.house 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 is 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 dot 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.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.house 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 when I create the object for the first time because of init 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 dot 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.pi 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 invalid 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 privet drive but because python knows that wait a minute you're trying to assign that is set of 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 student.pi 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 privet 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 Getters and Setters it's just for the purpose so that we can find our um that function 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 Getters we just have just one argument and if we use Setters is always going to be two arguments it's not 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 method 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 this Setter so it's better design and that's why I manually retyped it at first but then I deleted it from init 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 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 dot underscore 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 setter this one for name so the convention is at name dot Setter y 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 at name Setter and Define another function also called name but the key thing here is that it's not 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 dot underscore 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 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 student.pi 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 student.pi 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 Hogwarts 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 houses 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 on line 30 and I try to adversarially do something like this student.house equals quote unquote number four privet drive we know this won't work because my Setter for house is going to catch this watch again python of student.pi uh let's type in Harry let's type in Gryffindor which will at least pass our check that's induced by init 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 adversarily tragically look what you can do you can change dot house to be dot underscore house why will 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.pi let's type in Harry let's type in Gryffindor which is correct but Watch What Happens now oh my God we slipped through so what was the point of all of this emphasis from me on doing things the right way the pythonic 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 too that's an even greater effort by programmers to say really don't touch this but but technically speaking there's nothing stopping you or me from circumventing all of these mechanisms 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 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 2 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 stirrer it takes optionally a parameter called object here the default value of which is just quote unquote which allows you to create an effect an empty string a blank string if you will but any time 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 lower case by calling a method called Lower a method that the authors of pyekathon built into the stir class but it's been there from the get-go so this notion of methods is not even new today you and I've been doing it for this long if you've ever called strip to remove the leading in the trailing white 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 lower case and strip white space from the beginning and end let's do another list anytime you've created a list either either syntactically with square brackets or literally with list open parenthesis close 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 and optional iterable something that can be iterated over like one comma two 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 call depend that comes with the list class that per the X here 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 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 vs 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 type dot Pi just so that I can poke around inside of some values and type dot 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 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 I am here so let me go ahead and run python of type.pi 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 type.pi 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.pi there it is a list is a class 2. 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 lower case and I went to Great Lengths of creating my student class to have that capital S and 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 D2 capitalize the first letter as I did in something like student capital S but list open parenthesis close parenthesis is identical to really just two empty square brackets if I clear my screen and run type.pi again you see the exact same thing the class is called list let's do one more let me change the list to B naught 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.pi enter and there it is class dict 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 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 addict object is indeed the class dict itself so this is to say that is new as a lot of today's idea 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 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 paints and such sometimes 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 decorator 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 mean by this well let me go back to vs 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.pi and in hat.pi 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 encode 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 house that student should be in all right well let's go ahead and do this in hat.pi 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 hack 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 lower case 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 lower case equals Capital student open parenthesis close 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 dot 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 onto 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 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 source 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 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.pi 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 init 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 instance variable plural that equals this list Gryffindor comma Hufflepuff comma 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 to 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 it's 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 in 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 too is General convention anytime you have a list of things that who knows maybe will 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 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.pi 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 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 random and then below that let me go ahead and clear my terminal window and try again python of hat.pi crossing my fingers seeing where Harry is going to end up and okay Harry as of now is officially in Hufflepuff despite everything you've read or seen well let's run this again let me clear my window and run python of hat.pi 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 tests 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 I was about to say real world entity but really a fantasy world entity and indeed that's a perhaps common heuristic 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 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 and wrote more code you could imagine writing one program that has a list of students many more students 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 context 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 passed a reference to self the current object but sometimes you just don't need that sometimes it suffices you just know what the class is 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 and or functionality that is just somehow conceptually related things related to a Sorting Hat 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 init 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 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 hack because again there's 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 clsy well if you wrote c-l-a-s-s that would actually conflict with the keyword class that we keep using up here so the world realized that oops we can't reuse that same phrase here so let's just call this class this is useful in some contexts including this one why well notice what I can now do I can now change self to be just class why because houses now not an instance variable accessible via self-dot houses it is now a class variable accessible by a class dot houses or technically cls.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 altogether I'm going to capitalize the Hat on this new line 13 and just say hat dot sort quote unquote Harry so what have I done I've not bothered instantiating an object of type hat I am just accessing a class method inside of the Hat class that you know what is just gonna work this is how class methods work you use the name of the class capital letter and all dot 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 hat.pi 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 he said 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 cell dot houses when you when we remove it we uh and we pass the data the variable is created itself why we remove the salt so in the previous examples both of the Hat demonstration and also all of the student demonstrations we were uh creating a student object by calling student capital S open parenthesis close parenthesis with eventually name and a house passed in and then we were using the done 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 as 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 object-oriented 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 object-oriented programming but to solve somewhat different problem well what's the difference between the class hat and I don't know like a function of head a good question so why are we using a class at all and not just having a file called hat.pi 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 undo this indentation I 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 hat.pi 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 could 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 that too was another solution to the same problem you could Define your own modules or packages put some of your data and or functionality in there and that's fine too and sometimes which one you should use overlaps if you're familiar with Venn 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.pi and reopen student.pi as we left it earlier and let me go ahead and simplify it just a little bit I'm going to go ahead and get rid of the properties on up 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 adversarially try to change Harry's 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 student's name and the house and the printing thereof this is by nature of classes and object oriented programming theoretically 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 why well 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 a 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 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 in 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 therein 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 yielded the chickens 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 dot 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 dot 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 sees 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 convention called CLS for class which is just going to be a reference to the class itself mines 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.get just tells me what's going on I'm gonna 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.pi 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 a 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 run python of student.pi so far so good Harry Gryffindor okay uh and indeed Harry's from Gryffindor the reason Michael it does not matter in this case is because we're not actually calling 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 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 in 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 with an 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 object-oriented 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 what let me propose that we Implement over in vs code here a brand new file called wizard.pi let me go ahead and run code of wizard.pi and then let's start as before defining a class called student and let's go ahead and first Define the underscore underscore 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 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 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.subject 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 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 the 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 Def underscore underscore init underscore underscore 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 got 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 at 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 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 parentheses a student inherits from or is a subclass of wizard which conversely is the superclass 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 her for a 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 is Wizard so super open paren close 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 dot init for both student and Professor alike now admittedly this syntax is definitely out there the fact that we're calling super in 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 close parenthesis is a way of programmatically accessing a current classes parent class or super class and underscore underscore in it of course is just referring to now that class is owned in this specialization method now per the 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 checking to make sure they're in 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 restoring in self.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 students 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 lower case and uppercase on the right respectively Professor quote unquote Severus 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 and 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 in method of the superclass 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 superclass as well any questions now on this idea of inheritance which is a key feature of a lot of object oriented 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 super 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 grandmother or your great grandfather or great-grandmother some of those properties can actually 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 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 inheritance path a good question how about one more question on inheritance can we have multiple arguments in super dot double underscore in it yes but in this case I'm only passing a name on line 18 and I'm only passing in name on line 10 why because on line two when I defined 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 Patronus if both students and professors have patronuses 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 captures hierarchically all exceptions we've seen thus far actually descend from or inherit from um 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 ASCII 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 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 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 functionality 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 parentheses 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 and 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 in 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 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 vs code here and let me go ahead and create a new Final file called Vault dot Pi so code of vault.pi and let me propose that we implement the idea of a vault at Gringotts keeping on theme wherein there's a bank in the World of Harry Potter and within this Bank families 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 galleons and sickles and Canucks 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 one reason the same let me go ahead and vault.pi 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 tuple 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 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 galleons some number of sickles and some number of Canucks I want the user 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 galleons whose default value will be zero sickles whose default value will also be zero and Canucks 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.gallians equals galleons and self.sicles equals sickles and self dot canuts equals Canucks 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 vaults ultimately but first let's do this let's create a vault for The Potters by creating by assignment a new Vault and let's say that the Potters have 100 galleons 50 sickles and 24 Canucks 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 stir 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 arguments 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 inside of which is self.gallians and then the word Galleon so I know which those are then let's do self.sicles and let's output the word sickles and then lastly let's output self.nuts and then Canucks here so I know in this string just how many of each of those coins I have in this particular family's Vault all right let me go ahead and run python of vault.pi changing nothing else except the stir method and now we see indeed that Harry has 100 galleons 50 sickles and 25 Canucks 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 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 rather than Harry's hundred 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.pi 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 150 and 25 respectively versus runs 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 rods 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 galleons equals let's do Potter dot galleons plus Weasley dot galleons that gives me a variable called galleons that has the sum of Harry and Ron's galleons let's next do sickles equals Potter dot sickles plus Weasley dot sickles and then lastly let's do Canucks equals Potter dot canutz plus Weasley dot Canucks 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 galleons 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 vault.pi and there we have it uh what was 150 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 volts together on the left and the right well it turns out in Python and through operator overlading 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'll see here is this one here underscore underscore add underscore underscore and you'll see that it very generically is described in the documentation is working for any object be it a vault or 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's on the right hand side of a plus sign thereby giving us a way of describing encode 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.pi 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 galleons and the sickles and the Canucks 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 knit and stir but let's add this third all right let me go into the class here and Define underscore underscore add underscore 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 volts 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 two 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 are contents up here in our implementation of that as follows let me go ahead and Define a local variable called galleons and set that equal to for instance the sum of self.gallians whatever's in Potter's vault in this case plus whatever is in Weasley's vault in this case which would be other dot galleons let me do the same for sickles self dot sickles plus other dot sickles and let me lastly do that for canutz so self.canuts plus other dot 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'd better indeed return a value from this add 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 Galleon signals and Canucks do I want this brand new Vault to contain well I want it to contain this many galleons this many sickles and this many knots so ultimately what we're doing in this implementation of add is adding together those Galleon sickles and Canucks 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 of vault.pi and hit enter and voila and 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 coding effect underneath the hood that python is doing this for two strings to concatenate them together to joining two 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 offhand let's do this let's create a stir and see what happens if I add Potter plus a stirrer stir up yeah okay so it would work I'm just figuring this out as I go here Eric so just to 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 in 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 dot galleons 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 gonna 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 this as 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 then 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 tuples 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 one was cs50 [Music] foreign [Music] this is cs50's Introduction to programming with python my name is David Malin 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 Lao 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 it's 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 round fairly broad topics that are rather essential for doing typical types of problems in Python it turns out there's quite a number of other feature 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 vs 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 dot pi and then how Moses dot Pi 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 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 Slytherin 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.pi 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 list of 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 students in students as we've done in the past and let me ask you a question now so if the current students 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 House's list then indented am I going to say houses dot 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 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.pi 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 Slytherin 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 use more that's built into the language python to solve this problem ourselves 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 automatically eliminated and now I can type 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 dot add so it's not append 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 blindly add add add all of these houses to the set and any duplicates already there will be gone python of houses dot pi 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 in other 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 that set how do you find an item in 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 Slytherin it is maybe an O instead of an eye will the for Loop look throughout each of those um letters in the house name uh it would compare the strings so if Slytherin appears more than once but is slightly misspelled or miscapitalized 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 lower case 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 dot Pi let's go ahead and implement the notion of a bank wherein we can store things like 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 variable 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 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 underscore 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.pi I would hope based on my own intuition 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 main 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 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 a 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 verbally 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 too is going to take a variable in argument n for number of dollars or coins and now I'm going to go ahead and subtract from balance using minus equals 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 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.pi 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 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 to value and now online 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 so if you want to change this variable you should write an Insight Dev function name in 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 fixes 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.pi 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 balance globally so all three functions can access it but clearly where we began as Elena noted we can't therefore change it so it 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've programmed 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 vs 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 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 me to edit this variable up above so now let me go ahead in my terminal window and run python of bank.pi I'm hoping to see that my balance is zero plus a hundred 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 latter Will Shadow so to speak the former that is you'll be able to use the latter 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 non-obvious to other readers as well other questions on globals or locals okay what if we decide some unbalanced 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 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 program recall that we looked most recently at this notion of object-oriented 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.pi get rid of the global variable altogether and actually use some object-oriented 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 the 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 zero thereby giving me an instance variable called balance initialized for this account to zero but I'm going to proactively remember how we also introduce 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 dot balance and I'm going to go explicitly and say this is indeed a property of this class now let me go ahead and re-implement those other two functions deposit and withdraw but in the confines of this class so I'm going to say Define 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 dot underscore balance plus equals n and now down here I'm going to do def withdraw self and 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 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 init 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 hundred dollars 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 underscore 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.pi and hit enter now you'll see that it just works just fine because in the world of classes in Python the 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 per diameter self so which way to do it for a reasonably small script wherein you are simply trying to implement a script that has some Global uh information like an account balance that you then need to manipulate elsewhere 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 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 re-implementation of the same idea but using full-fledged object oriented programming uh I just would like to ask uh what this property does what this property does so if I go back to vs 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 thousand to just give myself a thousand dollars 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 can 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 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 go back here to vs code and let me create a new file for instance called meows.pi and let's see if we can't implement the notion of a cat meowing on the screen so I'll do code of meows dot pi and in meows.pi let me go ahead for instance and Implement a very simple program that just has a cat meowing three times so how about this for I in the range of 3 go 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 pythonically 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 hard-coded 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 as 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 hard-coded 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 clearer to colleagues and frankly me tomorrow after I've forgotten what I did today to Define a variable like meows and set it equal to three and then instead of hard coding 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 meows 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 python 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 work in other languages though there's typically a keyword or some other mechanism syntactically that would allow you to prevent line three currently from executing so that when you try 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 typically manifests and in fact let me go ahead and change this around a little bit let me delete this version of meows 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 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 people that should should not be changed but you just want to indicate that visually by capitalizing its name so for instance if the default 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 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 dot meows to make clear that I want the meows 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 lower case 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 dot 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 and 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 meows.pi and there it is three of our meows meow meow it turns out that python is a 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 equal sign some other value and honestly python just kind of dynamically figures out what type of variable it is if it's 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 plus plus 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 did 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 altogether your 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 correctly 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 link your code with some other program before you actually release it to the world so how might we go about using these so-called typins 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 type pins and that program here is called My Pie 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 my pie and its own documentation is that 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 meows.pi as it currently was and let's Implement a different version of meows 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 to meow for instance n for number and inside of this function I'm going to 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 I've not bothered defining the variable as I am 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 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 meows.pi 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 and to sure 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 retains a string instead of an integer exactly the input function returns a string or a stir not an end 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 colon of 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 a 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 B dynamically typed not so strongly typed as to require these things to be true but if I run meows.pi type in three again the same error is there but let me go about trying this my Pi program an example of a program that understands type hints and if I run it proactively myself can find bugs like this in my code before I or worse a user actually runs and encounter something cryptic like this type error here let me clear my terminal window and this time run my Pi space meows dot Pi so I'm going to run my Pi 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 type stir expected end so it's still an error message but my Pi 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 mu using my argument to meow wrong I had better fix this somehow well I can actually go about in hint adding type hints even to 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 assigned it equal to the return value of input I could give my Pi in 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 pie 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 mypie of meows.pi and hit enter and this time notice that my pie 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 type in when used and analyzed by my Pi has helped me find a wait a minute I shouldn't be assigning the return value of input to my variable called number in the first place why my Pie has just pointed out to me that one returns a stirrer I'm expecting an INT let me fix this now instead alright 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 like we're just going to assume that the user types this in properly and now let me go ahead and run my Pi of meows.pi having not only added two types 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 pi and success no issues found in one source file now it's more reasonable for me to go and run something like python of meows and just trust that when I type in 3 at least I'm 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 code in the first place I provided these annotations these hints that inform tools like my Pi 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 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 using the correct type in the way that you're using 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 writability 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 my Pi 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 so the the situation essentially is that within the python ecosystem you can annotate your types in this way you can use tools tools to use those tight pins but today to python itself does not enforce or expect to enforce these conventions and larger code bases and professional code bases Commercial Code bases probably depending on the product project manager or depending on the engineering team they may very well want themselves to be using type hints 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 assumed that the meow function just 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 suppose that I accidentally did something like this rather than just getting the number and passing it to meow suppose I did this suppose I declared a number of 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 returning 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 meows 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 a stir instead well let me go ahead and run this code now python of meows.pi enter typing in three and you'll see a curious bug meow meow meow none but 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 eight because I'm assigning the return value of meow which is none to my meows 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 it's about 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 we with this new feature called type hints 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 gonna excuse me return none but now at least I can catch it like this if I now run not python but my Pi on my code which would be a habit I'm now getting into if using type hints check that I'm using all of my types correctly before I even run my program we'll see that now my Pi has found on line seven that meow quote unquote does not return a value and my pie knows that because I have proactively annotated my meow function as having none as its return value so now my Pi can detect that I should now realize oh wait a minute I'm being foolish here my 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 test 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 backslash n times that number n so it's kind of a clever one-liner avoids the need for a for Loop or something more involved than that to just say multiply meow backslash n against itself three times essential 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 Mouse 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 meows plural of variable that's of type stir because now meow does have a return value of typester itself per this type hint as well all right let me go ahead now and print meows but because each of my meows comes with a trailing new line the backslash and 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 three so if I run python of meows.pi now type in three there's my meow meow meow and now no mention of none questions now on type hints and these annotations in my pie and using them to defensively write code that just decreases hopefully the probability of your own bugs [Music] while the program don't take it as a strange why does the program not take it as a as strange 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 tight Pence or my pie can we not Typecast this data type uh 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 because it's not like C or C plus plus 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 Pi 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 itself is still a function it's not a type hint but the word int is being used in another way now in these type pins so this imp 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 hints 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 doc 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 meows.pi 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 doc 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 comments 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 in the end or three single quotes at the start in the end and python has built into it certain tools and certain assumptions that if it detects that there is a comment using this doc string format triple quotes on the left and the right it will assume that that's indeed the documentation for that function and it turns out in the python 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 functions 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 manually now it turns out if your function 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 the same triple quotes above and below now you might see your one sentence one sentence explanation of the function meows meow end times sometimes depending on the style and 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 param n colon and then adjust 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's sake for other programmers this function returns a string of n meows one per line and the return type of that value our type is going to be stir 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 doc 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 third-party libraries for instance cow say a few weeks back recall that I showed you what functions it had but if you read the documentation you might actually see that 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 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 because it does do these include 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 when 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 meows program to actually take its input not from the input function in the blinking prompt but from the command line recall in our discussion of libraries that you could use something like sys.org V to get at command line 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 command line 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 sis.org V equals equals one 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 meows dot Pi just so that the user knows that the program itself is called meows.pi all right now let me go down to my terminal window and start to type python of meows.pi and at this point notice that the length of sys.org V Should indeed be one why well python the name doesn't end up in sys.rv at all ever but meows.pi the name of the file does and it's going to go in sys.org v0 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 meows three enter then I'm going to they 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 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 dash n which semantically means this number of times then often 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 Dash N3 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 meows.pi Space 3 well what does the three mean at least with syntax like Dash N3 especially if you've read the documentation for this program ultimately oh Dash N 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 Dash N3 well if I'm using CIS like this I could do this L if the length of cis.org V equals this time 3 because notice there's one two three things at my prompt so sys.org V 0 1 and 2 three things total separated by spaces if it equals three and let's be safe and sis.org V bracket one equals equals dash n then let's go ahead and do this let's go ahead and convert uh sis dot org V of 2 to an integer and assign it to a variable for instance called n and then let's go ahead and do this for underscore in the range of n let's go ahead and print out some of these meows 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 dash n and a number if indeed the second thing they gave me in sys.org V of 1 equals equals dash n then I'm going to assume that the next thing sys.org V of 2 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 alright 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 into the command line with something like these command line arguments like dash n 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 complicated right let's imagine a world where I don't want to support just dash n maybe I want to support Dash a and dash B and dash C and Dash D and a whole lot of others or heck at that point I should maybe give them words so maybe it's a dash 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 dash n or maybe it's dash dash number but you can imagine just how complicated the code gets if now you want to support Dash N Dash a dash b c and so forth you're gonna 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 dash n first or is it second or is it third or is its 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 this is why as always there exists 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 cs50s team writes in Python we very frequently use ARG parse 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 dash n or Dash a or Dash b or Dash C ARG parse is a library that per its documentation just handles 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 now and instead import ARG parse ARG parse stands for argument parser to parse something means to read it 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 that could call it anything I want I'm going to set it equal to the return value of ARG parse dot argument parser with a capital A and a capital P A Constructor for a class called argument parser that comes with python itself within 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.add underscore argument so that's apparently a method in the parser object I'm going to add an argument of dash 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 dot parse args and by default parse arcs is going to automatically look at sys.org V for me I don't need to import sys myself I can leave the argument parser its code to import sys look at sys.orgv and figure out where dash n 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 dash n a dash 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 numbers of arguments and that many mouths rather I can do this for underscore in the range of the int conversion of args.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 the object returned by the parse arcs function for 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 than my if and my L if and my ORS and my ands 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 meows.pi 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 dash n three enter so it does work but if I don't cooperate this actually seems to be a worst version if I don't pass in dash n in a number it just errors with a type error it 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 Dash H or dash dash help 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 meows.pi space Dash H I'll do it again let me clear my screen and this time do dash dash help 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 and Community Computing and we've kind of seen it in Python's documentation before this just means that the program's name is of course meows.pi square brackets as almost always in documentation means it's optional so I don't have to type Dash H but I can I don't have to type dash n and another value but I can and then down here is some explanation of these options and more reversely showing me that I can also do dash dash help and not just Dash H 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 dash n argument that just explains what Dash N 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 I'm going to run python of meows.pi Dash H or equivalently dash dash help 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 end a metal variable if you will is just indicating to me that I need to type a number by convention after the lowercase dash n 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 sys.orgv myself so we just need to add a little more 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 dash n 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 Arc parser to make sure that the value of dash n 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 it 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 meows.pi and hit enter this time no arguments and now it meows why because I specified that if I don't as a user specify dash n it's going to have a default value of 1 apparently and I don't have to convert that value from a stir to an end because I told our parser please just make this an INT for me any questions now on artparse or 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 that and contain what does args.n contain it contains the integer that the human typed after a space after dash n a 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 exception 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 in well let's see what happens so python of meows.pi dash n dog it's 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 the 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 turn to vs code closing out meows.pi and creating a new file for instance called unpack dot Pi so code of unpack dot pi 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 Malin wouldn't it be nice if we could record a 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 some other data structure and putting it immediately into two variables so let's do this here let me go ahead and call 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 Malin 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 curly braces first if I just want to greet myself or any other user is 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.pi I'll type in David Malin 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 galleons and sickles and Canucks 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 Gringotts The Wizarding Bank based on how many galleons sickles and Canucks 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 galleons and sickles and Canucks like this and then it's going to return the formula which I admittedly had to look up myself and it turns out that the formula for converting galleons and sickles to canuts would be this galleons times 17 plus sickles then times all of that by 29 and then add in the individual Canucks not sure in what detail this came up in the 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 a hundred galleons 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 rather pass the return value of total to print and then just for clarity let me write Canucks at the end so I know that the unit of measure here is indeed canutz in total all right now let me go ahead in my terminal window and run python of unpack.pi and hit enter and it turns out mathematically that if I got my math correct a hundred galleons plus 50 sickles plus uh 25 cannuts equals in total 50 775 Canucks 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 150 25 it just because for whatever purposes in this story I have all of my coinage in a list in this order kind of a purse or wallet of sorts well how can I pass this in well I'm not going to hard code 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 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 0 1 and 2 respectively from left to right so all I'm doing here now is passing in the first element from that list as galleons the second element of that list as sickles and the third element of this list as Mike nuts 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 make sure I haven't broken anything unpack.pi 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 galleons yeah I'm passing a list to galleons and nothing for sickles and Canucks and notice those don't have default values there's no equal signs on that first line of 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.pi enter type error and that is probably what you might expect like I'm messing up with the types here and I re I'm required to pass in two positional arguments sickles and Canucks that were not even passed so I've definitely aired here but it certainly seems unfortunate 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 argument it's 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 150 and 25 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 3 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 150 and 25 respectively which is perfect because now it's going to line up with galleons sickles Canucks respectively so now when I run python of unpack.pi 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 contexts 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 tuples sets dicks dictionaries as well tuples yes sets I don't know wrong Shin I don't know if order is preserved no oh is that no it does not or you know you're checking order's 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 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 how can you use unpacking to get the value uh for example 10 plus 50 plus 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 we have declared we we declare some default values and if you use these asterisk points will it work right or will it 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 dot Pi enter another type error this time it takes three positional arguments before we're 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 positional uh arguments whereby we trust that the first is galleons the second is sickles the third is knuts 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 galleons I want to still equal 100 sickles I want to equal 50 and Canucks 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.pi enter and there we have it still 50 775 Canucks 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 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 galleons quote unquote colon 100 for 100 of those sickles quote unquote and 50 of those and knuts 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 galleons sickles canuts and three values 150 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 galleons strings like this coins quote unquote sickles in square brackets there and then lastly coins square brackets quote unquote Canucks 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 Galleon sickles and canuts into your function respectively let's make sure I didn't break anything let's rerun python of unpack.pi and we're still good now how could we get to a situation like this well as always imagine this program's 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 coin 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.pi we're getting another type error missing two required positional arguments sickles and Canucks 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 asterisk 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 galleons equals 100 comma sickles equals 50 comma Canucks equals 25 and so it has the similar effect to the list unpacking but that just passed in the values 150 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.pi 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 Purser or uh wallets in there in a list as we did earlier or I can store it a little more versus with even more specificity using a dictionary instead and so to 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 the 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 can we have instead of having a constant 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.pi we're 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 English values we get 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 the default value a good question if you if we did have default values up here for instance equals zero equals zero 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 very attic 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 galleons and sickles and Canucks 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 one and so I'm going to go ahead and use this syntax here star args which indicates that that this function is indeed very attic 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 kwrs 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 the world tends to use args and Key kwrgs 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 arguments are and let me quite simply print out those args this is not something you would typically do you 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 this 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 didn't bother giving them names just yet like galleons and sickles and Canucks 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.pi and hit enter and you'll see that the positional arguments passed in are apparently this a sequence 150 25 but notice this if I clear my terminal window there and pass in 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 150 25 and 5 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 tuple 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 an args but KW args again the positional arcs in this syntax come first the named arguments KW arcs come second that's 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 galleons equals 100 and sickles equals 50 and nuts 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.pi and hit enter no problem what kwrx 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 in some of the functions we've used to date we didn't necessarily see it called args or necessarily see it called KW args 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 asterisk 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 the 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 def 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 two the next one of which might be n 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 apply 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 variatic ARC functions whereby you can pass in a variable number of arguments what you now have via this args and KW Arc 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 arguments any questions now on these types of arguments what will happen if you print quarks and the argument is like a lift 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.pi 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 KW args 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 [Music] how about this next it turns out that a few other tools we can add to your tool kit 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 variables 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're using all that time were in fact objects objects that were came from certain classes and those classes were templates of sorts blueprints via which you could encapsulate both data and functionality therein what we also saw along the way some hints of a third Paradigm of programming that python also to some extended supports 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 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 unpacked up high 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 dot 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 yells something like this is cs50 properly capitalized not in all caps now let's go ahead and implement this yell function with def yell that's going to take for now a single uh word or phrase 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 Dot Upper so phrase Dot 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 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 dot Pi 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 is 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 yell 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 quotes 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 type hints or annotations for now but I'll just assume that Yale has been defined now as 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 dot Pi 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 uppercased 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 upper cased list a pen to it the current words uppercase version so this is a way of creating a new list called uppercased 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 yell dot Pi 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 yell dot pi 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 C ps50 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 Yale three arguments now I don't want to do something like change the definition of words to take in like word one word two or 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 dot Pi this is cs50 is in all caps but it's just a little better right because now I can treat yell 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 uppercase 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 and python can I do just that let me go back here to vs code vote and let me propose now that I re-implement this as follows I get rid of all three of these lines here getting rid of that Loop in particular let me still declare a variable called uppercased 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 Dot Upper I'm not using parentheses open and close at the end of stir Dot Upper because I don't want to call it now well 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 Dot 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 gonna unpack them and print them all out so let's run this again python of yell dot Pi enter and voila it's still working but the code now is even more tight 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 that's using a feature known as a list comprehension and it's 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 pen and a pen but to do everything in one dare say elegant one-liner so how can I go about using this notion of a of a list comprehension well let me go ahead and do this in yell.pi and vs code 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 words list I can do this word Dot Upper for word in words 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 append and a pen and append but that usually takes two three four or more lines this list comprehension 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 brackets 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 conditionals 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 uppercasing every word in the list a good question other questions yeah um is this is this functional programming or I mean this particular thing you're using words Dot Upper for word in words not necessarily this is more of a feature of python I would say yeah map was uh one uh very specific incarnation of there of our use of Lambda and passing it in as a key attribute to the sort function 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 l.pi and close my terminal window and let me create a new program here whose purpose in life maybe is to take a 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.pi I'm going to go ahead and copy paste from before really my list of students at least Hermione 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 lists 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 student's name for each student in the students list but but but if the student's 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 information 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 the students whose house happens to be Gryffindor so when I go ahead and run this with python of gryffindors.pi and hit enter you'll see huh nothing actually happened here well that's because I didn't finish the program let me go ahead and actually finish the program with this how about for each Gryffindor in gryffindor's 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 in the movies you'll know that only three of these four students are actually in Gryffindor and if I run python of gryffindor.pi there we see Harry Hermione and Ron butt 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 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 which turns 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 Dot 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 gryffindors.pi 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 sorted on gryffindors 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 pythonofgriffendors.pi 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 in 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 in the previous version where everything is stuffed into one like once the if we check for the style of the code then want it don't have a problem with it because it's less readable so with a formatter like black have a problem with the style of some of this code the previous one where the everything was stopped 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 looks like if we go far enough back give me a few more undo's which looked like this ultimately let me go ahead and run black on gryffindors.pi and you'll see that I actually it reformatted ever so slightly but I proactively fix 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.pi and this approach of using a list comprehension or filter yeah when when using filter instead of calling the function is Griffin there can you use it 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 mean if you can write the return as is SQL script in the inside yes indeed in fact so recall that we indeed use 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 Gryffindor 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.pi 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 come 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 code here and let me propose now that I do this let me go ahead and initially do it the old-fashioned way here as follows let me go ahead and simplify and get rid of the houses all together so that we can focus for now just on a list of students names I'm going to go ahead and run students I'm going to go ahead and write students e equals quote unquote terminal 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 and 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 student 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 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.pi 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 I 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 object from the next and if we look past Harry and Gryffindor there's 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 in 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 gryffindor's variable will equal the following list comprehension inside of that list I want a dictionary structured with someone's name and their name so 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 indicate 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 dict objects from well for student and 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 python of gryffindors.pi 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 cryptic to read at first glance but once familiar with list comprehensions and this sort of syntax it's 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 colon Gryffindor Ron colon 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 constructed from the list of students one at a time so when I print this now the syntax will look a little different because it's not a list of dictionary objects it's just one bigger dictionary object itself but now printing gryffindors gives me Hermione colon Gryffindor Harry colon Gryffindor and Ron colon 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 one to two to three unfortunately when you do something like this for student and students you can print out the student's name quite easily of course if I do python of gryffindors.pi 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 a different type of for Loop instead of this why don't I try this so maybe I could do 4 I in the range of the length of the students 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.pi it's close but you know these aren't programmers they don't necessarily think of themselves as zero index Termini 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 plus 1 of course and then the student's name so if I clear my terminal window and run python of gryffindors.pi once more now we have this enumeration one 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 vs 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 plus 1 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 0 1 2 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 toolkit allow us to equip you with one final tool for your toolkit namely this ability 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 lull 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 a program called sleep.pi that allows me to print 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 times I so the first iteration I'll see Zero sheep the second iteration I'll see one and then two and then however many specified by n ultimately minus one all right let's go down into my terminal window here and run python of sleep.pi and I should see indeed after typing in say 3 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 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 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 man and let's Factor some of this out wouldn't it be nice if I could for instance just call a sheep function as by 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 specifies how many sheep do you want to return and so that we can test this as with a unit test so 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.pi 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 first create a flock of sheep that's initially empty using an empty list then for I in 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 main can handle the printing 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 hundred 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 thousand but ten thousand sheep well that too seems okay 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 we'll we will speed up time 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 one 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 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 servers memory or CPU the brains of the computer's capabilities because it's just trying to generate massive massive massive lists of sheep one 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 thousand sheep 10 000 sheep once you cross some threshold it just stops working all 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 two three four at a time well we could do that but that's really a step backwards that rather contradicts all of the Lessons Learned of the past few weeks where generally not putting everything in Maine is a good thing generally having an additional function that you can then test separately with unit tests 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 a python are documented in the official documentation they're in but what you'll find ultimately that it all boils down to this keyword here yield up until now when we've been banking 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 it 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 whereby 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 the 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 for Loop will keep working and I will keep counting from zero to one to two all the way up toward one 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 one 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 3 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.pi let's try one 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 and 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 the same feature here is returning what will technically Now call an iterator yield is returning an iterator that allows your own code your own for Loop in main to iterate over these generated values one at a time how how does this yield actually works under under the hood 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 suspect spend 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 pulling in every iteration the program will return the memory to the system so the program will not crack 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 Loops in your own code even though this is an infinite it's just really long Ctrl 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 can additionals 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 see that you can now use those same kinds of conditionals now to do fancier things with list comprehensions and 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 to pass file i o 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 disk 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 in fact be quite messy 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 say dot Pi in vs code and I'm going to go ahead here and first import our own friend import cow say I'm going to import this new library here import Pi ttsx3 the python text-to-speech library and now per its 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 cow say we can do cow say dot Cal of this turns out this new library can allow me to use its own engine to say this as well but then ultimately I'm going to have to run the engine dot 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 cal 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 Learn 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 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 a Google or friends who are more versed in this language than I and so having that instinct having that vocabulary Vari 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 pythonofsay.pi crossing my fingers one final time in hopes that I've not made any mistakes or bugs and here we go python of say.pi prompting me what's this how about we end on this note here [Music] this was cs50