 You'll learn how to become a competent Python programmer by learning the fundamentals of the language in detail. You'll learn how to navigate complex data structures and accumulate results from them. And you'll learn how to convert data into a format that can be used by other programs. At the end of the specialization, you'll be able to write Python programs of a few hundred lines. You'll be able to use and integrate Python modules into your code. You'll be able to use external tools like APIs by reading their documentation as well. We start from the beginning and we don't assume any prior knowledge, but we do go deep into the fundamentals of Python to be sure that you understand every aspect of code. So, you want to say something about what's our runestone interactive environment? Yeah, so the runestone interactive textbook allows you to interleave learning materials with active code assessments that will allow you to actually write code. And we find that writing code is really important because even though you can learn how a concept works in theory, so you might know how some particular feature of Python works, it's really important to actually write code to gain more of a working understanding and to know how to actually apply those concepts in practice. So, there's also the way of the programmer segments. So, most of the course is about how to use Python and learning about Python features. The way of the programmer segment is more about how programmers can and should work. Programming is a little bit more of an art than a science. There's lots of correct ways to do things, but there are best practices. So, there are things like how to write programs incrementally. In the way of the programmer segments, you'll also learn about how to write good automated test cases. So, that's going to come in course four. Until then, we are going to write those test cases for you. Lauren has created a whole lot of assessments where not only can you run the code in the browser, but it'll tell you whether you got it right or not. And you get that immediate feedback and you can try it as many times as you want. In fact, we've set up the assessment so that you have to get everything right, 100% in order to pass the assessment. And the reason for that is we really want you to build mastery so that you don't go on to the later stuff until you've got the early material really solid. You'll also notice that in all of the projects that you do, you'll find ways of translating the concepts that you learn in the courses and throughout the specialization into your real life. For example, different ways of building programs that might be fun in your job or your school or your work or whatever it is that you do. So, one of the things that I really like as I've watched you all put this together is in Python for everybody, and you kind of already said this, in Python for everybody, I really focus on the program. If you get the program, it's like you win, you know, you get the gold star. And we didn't have the time or the luxury to really understand what was going on inside the program. We're just like, we got the program done and we got to move on to the next thing. But with some of the stuff that you have in Runestone, you get to say, what's really going on inside of the program and how does this really work? And that's part of the mastery is so that if you can't, as a programmer, kind of put yourself inside the program and understand how the program is actually functioning, it is difficult to write more sophisticated programs. And so, that's where, even though this technically is a beginning course, I think it's really important for people to take more than one beginning course because you have to go over the same material over and over with, in a sense, deeper understanding each time you go through it. Yeah, we have this great code lens tool that I think you're referring to that lets you visualize what's happening in the execution of the program one line at a time. And you can go forwards and back and see what actually was the value of that variable and when did my list change what its contents were? And so, it gives you a way of thinking about it. It's really great for debugging so that you don't have to just do trial and error. Let me change something in the code. You can really think through what is a program. So, another thing that the students always ask me at the end of my course is what next? And I think that it's kind of cool that you've built into this specialization kind of a step into what they're going to do after this. Chris? Yeah, so one of the things that we've added to this course at the very end is a project course and that's really to focus people on how to take other APIs that might be out there or packages and use them and do something novel with them outside of just learning. And it gets to this repeated practice comment that you made. And for that, we're actually doing it within the Jupyter environment. So, just like you need repeated practice with APIs and with Python fundamentals, there's so many different places that you can write Python code and Runestones, one of them and the tools you use in Python for everyone are one of those. Jupyter is one that's quite common and we teach that in the data science specialization that students could follow this with. And there's other environments too that we're trying to really showcase a diversity of learning environments and production environments for Python. Programming is not one environment, right? It's not like you have this one thing and you type this stuff in and that's all the programming. When you're out in the real world, each job often has different kinds of environments. Yeah, and practice is so important in the context of programming. I think Lauren has written some great examples of practice problems for you to work on throughout the course as well. And we have this great practice tool that you'll get to see where it represents to you for review some questions that you've already seen in the past. And it keeps presenting them to you more frequently if you're having trouble, less frequently if you're showing mastery of them. And it's a way to really reinforce what you've got. So look for that practice tool. It also has these fun fireworks that'll show when you've done all of your practice problems for the day. So as you can tell, we're really excited to share this material with you. And we hope you have a lot of fun and wish you a lot of luck. Here at the University of Michigan, our school colors are maize and blue. You might think of them as yellow and blue, but we call it maize and blue. And if I travel anywhere and I have a Michigan logo thing on, someone will come up to me in the airport and say, go blue. So on three, one, two, three. Go blue! Welcome. We're delighted to have you. And if you're just joining us for the first time, we're also glad that you're with us. At this point, we're assuming that you're comfortable with functions, with dictionaries. You can extract data from nested data structures and that you are comfortable with Python's list of comprehensions. If you're joining us for the first time, please make sure to look at the video on the Runestone environment because we'll still be using that for much of what we do here. Thank you for joining. I'm Paul Resnick. We're both faculty members at the University of Michigan School of Information. In this course, you'll learn about classes. Classes are nice because they allow you to combine the methods and data that are relevant to some problem into one nice, easy-to-use package. In fact, classes are so nice that some programming languages like Java require you to use classes in order to use the language at all. Python makes classes optional, but it can make your code much easier to read and write. You also learn about class inheritance. Class inheritance allows you to reuse code, which can make your code a lot more concise and easier to read. You'll also learn about test cases in this course. It's kind of an advanced topic for an intro programming sequence, but we think it's really valuable to get into the habit of writing test cases from the very beginning of your programming career. A test case is a way of specifying what a class should do. If you write some test cases and then you implement your function, if it passes the test cases, you know that the function is implemented correctly. If it doesn't pass, you know you did something wrong with the function. And you'll also learn how to handle exceptions. So you've probably encountered runtime exceptions before, and whenever you encounter a runtime exception, so when you have a variable that doesn't exist, when you try to divide by zero, whenever something like that happens, then Python just stops running your program and gives you an error message. So we'll learn how to actually handle these kinds of runtime exceptions and give you more control over how Python evaluates your code. In the project for this course, you'll use what you learned and write a game of Wheel of Fortune, and you're going to use classes to represent the human player and the computer player, and you'll use methods to specify what's the best example of a game that's going to be used in the future. So, let's get started. Dr. Chuck, Chuck Severance, will make a cameo to show you how classes and inheritance make it easy to implement web programming using the Django framework. Like previous courses, we'll mostly have screencasts with code examples, but we'll occasionally come on screen in order to introduce words of wisdom or to introduce topics. So, let's get started. Bye for now. Welcome back. So, in this piece of code, here we set the instance variable for X for both 0.1 and 0.2 on lines 8 and 9. Now, even though you can do this in your Python code, this isn't the way that you should set instance variables. So, instead you should set instance variables in what's called a constructor. Now, a constructor is a special method that's meant to initialize including instance variables. So, the constructor is named what's called underscore underscore init underscore underscore. And it's just a special method with this name underscore underscore init underscore underscore. Now, I'm going to call this instead of underscore underscore, I'm going to say dundrescore. So, that would make this dundrescore init dundrescore. But instead of saying dundrescore init dundrescore, I'm just going to say dundrescore init for now. Okay. So, we want to define our constructor dundrescore init. So, the way that we do that is we define this method and we can say def dundrescore init dundrescore and init just like every other method takes in self as its first argument. And I'm going to pass in two more arguments x and y. Now, in our constructor I'm going to say self.x equals x in self.y equals y. Now, if I delete these lines and try to run my code as is then I'm going to get a runtime error saying that my constructor method takes exactly three arguments but only one was given on line nine. And what that's saying is that okay, so it takes three arguments but self was already provided when we called our constructor. We need to pass in values for x and y as soon as we create instances of point. And so here I'm going to pass in values five and ten for this point and one and two for point two. Now, what happens here for point one, I'm passing five in for x and ten in for y and for point two, I'm passing one in for x and two in for y. And rather than setting the instance variables later on then what we're doing is we're setting the instance variables in this constructor. So when we say self.x equals x for point one, that's setting point one dot x to be five and point one dot y to be ten. When we do this for point two then we're setting point two dot x to be one and point two dot y to be two. So now, if I call get x on point one so print point one dot get x then I should get five. If I print out point two dot get x then I should get one. That's all for now, until next time. Welcome back. So last time we talked about creating classes and again the way that you create a class is you say class and then the name of the class which usually starts with the capital letter so I'll say class point. I'm going to leave open and closing parentheses here and then you usually declare constructor method which is underscore init underscore and every method takes in an argument self and in the case of point we'll call x and y the arguments of the constructor and then we set the instance variables inside of the constructor so I'll say self dot x equals x and self dot y equals y. In this lecture I want to give some more detail about what actually happens when we construct an instance of this point class and how python actually searches for instance variables and methods so we construct a new point I'll say point one equals point and then we need to pass in values for x and y so I'll say that x is equal to ten and y is equal to one hundred for point one so let's suppose that we declare two methods get x which returns self dot x and get y which returns self dot y when we declare these methods what python does is it has some internal representation of the class itself now we've talked about the metaphor of classes as factories so I'm going to visually represent a class as this factory like object so you can imagine these as the smokestacks and this is the factory so when we have an init method we're saying that we have one method inside of the class called underscore init and this is a function like object that lives within the class so it accepts three arguments it accepts self and it accepts arguments for x and y so this method in underscore init constructor lives inside of the class and then when we have get x this method also lives inside of the class so we have this method inside of the class get x in this case it takes in one argument which is self and then we have the method get y and again get y lives inside of this class now on line ten when we create a new instance of point what this is doing is it's asking the class to create a new instance and I'm going to represent this instance like so and every instance has a set of instance variables in this case the instance variables are x which we set to ten and y which we set to 100 now I want to go into a little more detail as to how exactly we set these instance variables to 10 and 100 in other words what exactly happens when we say point ten 100 so I'm going to erase this instance for now and let's start from scratch so when python evaluates the statement point ten 100 then what it does is it first creates a new kind of blank slate instance so it creates a new instance of point and it doesn't have any instance variables the next thing that python does is it asks does this point class have a constructor in other words this underscore init method in the case of point there is a underscore init method so what python does is it calls that underscore init method on this empty instance so what it's going to do is it's going to take this instance and pass it in as the value for self and then we call the constructor and all of this is done before we even have finished evaluating the statement so we take this instance in and that's the value of self and then in this case we're also passing in two additional arguments we're passing in 10 for x and 100 for y and when we're passing in values for x and y these are just function arguments so in other words even though it's to be the name of what's going to later on be an instance variable there's nothing special about this value x now we're calling the constructor underscore init and we're passing in our new instance which is blank and we're passing in again values for x and y now on line 3 when we say self.x equals x then what that does is it sets the instance variable for this instance so it's setting the instance variable x to whatever this value x that we passed in is so in this case we passed in 10 for x so we're setting the instance variable for this instance x to 10 same thing for y in this case we're setting y to the value 100 because that was what was passed in so now we have this instance and it has two instance variables x and y that's all for now until next time welcome back so suppose that we have some data and we want to use classes to represent that data so that data might come from a file it might come from an internet source or in the case that I'm going to go through right now it might come from something that we just hard coded so in this case I have a list of city names, populations and state so I have city name, Detroit with population 180,250 in state Michigan and I have Ann Arbor population 117,070 state Michigan etc so Pittsburgh this is the population state is PA Mars, small population in Pennsylvania, New York large population in New York so let's suppose that I have this data and let's suppose that I also zip this data together so zip is going to take these separate lists and create a list of tuples so if I print out what's the value of city tuples I'm going to see that I have a list of tuples where every city name is coupled with its population which is coupled with the state so suppose that I want to use classes to represent this data the first thing that I would ask is what data do I want to be able to put into every instance so what should every instance have so what should instances store so in this case let's suppose that I care about all three of these things so let's suppose that I care about the city name the population and the state so I want every instance to store the city name population and state so then I would ask what do I want every class to represent in this case it's a little bit obvious every instance should represent an individual city and every individual city is going to have a name population and state and I'm going to call my class city so let's define our city class I'll do that by saying class capital C city and in the constructor I'm going to accept a name population and state and I'm going to set instance variable so self.name equals n self.population equals p self.state equals s and let's suppose that I want to have a str method so def underscore str and I want it to return the city name state and population so I'll do this.format self.name self.state okay so now that I have this list of city tuples and I have a class to represent every individual city I want to take this list of city tuples and create a list of cities so let's suppose that I want to have a list of cities so I'll say cities I'm going to start it out as an empty list I'm going to loop over every tuple so I'll say for city tuple and city tuples for now I'll just print out what's the value of city tuple and I can see that I get every tuple on a separate line if I wanted to I could set name population state equal to city tuple if I print these out name population and state and I'll see I have the city name population and state in different variables if I want to create a new city with that name population and state I'll say city equals a new city with name population and state and now city is an instance of the city class so if I print out what's the value of city tuples and I also need to spell out population in my str method so now I'll see that I am actually calling this underscore str method on my list of cities if I wanted to add that city to my list of cities I could say cities dot append city and by the end of this for loop cities is going to be a list of city instances so I can say print cities and you can see I have a list of city instances so some shorter ways of doing this one thing that I could do is I could use list comprehension so rather than having all of these lines I could use list comprehension to say that cities equals a new city with name population and state for every name population and state in city tuples now if I do this and I actually print out cities then I'll see that I get a list of city instances as well one really short way of doing this is actually if I do t I can actually add this star t what star does is it takes this tuple and expands it into a list of arguments so this constructs the same thing I'm going to prefer however to instead explicitly get out the name population and state that's all for now until next time welcome back so let's suppose that we declare this class to represent a point on an x, y plane so again our class is called point we have a constructor that takes an argument for x for a y and assigns two instance variables x and y to whatever is passed into the y plane here we also have methods that get the x value and get the y value and we have an additional method that determines the distance from the origin so this is if the point is at x and y it's going to get this distance from the origin and return it as a float so let's suppose that we create a point at 7 and 6 if we print out what is the value of this point p then python gives us back just information saying that this is a point object it has no information about where the point actually is so for example if I had a second point at 8 and 9 and print it out p2 I have no way of telling that p and p2 are different points so classes can have an optional method called underscore str so def underscore str underscore and just like every other method it accepts self as the first argument and what this underscore str method does is it tells python how to represent that object when you actually print it out so if I specify that str should print out just point by returning a string point now when I print out both of my point instances you can see that I get point if I instead print out point 123 then I'm going to print out point 123 so whatever gets returned by this underscore str method is what gets printed out when we convert this point object to a string in order to print it so for points we might want to have something like point and then maybe the x and y position so what I might say is point at x and y by saying point.format and self.x self.y now when I print out point p then I'm going to get point at 7 and 6 because here 7 gets substituted for self.x 6 gets substituted for self.y and self.x goes into the first slot, self.y goes into the second slot and so now I can tell both of these points apart and when I print out the instance then I actually get something useful for point so when you create a class you often want to set the underscore str method in order to get more readable and understandable things to print out when you actually print out any particular instance that's all for now until next time welcome back so suppose we have our point class from before and we have a constructor underscore init underscore and underscore str underscore to represent how we represent any instance as a string now suppose that we have two points as well .1 at negative 5 and 10 and .2 at 15 and 20 so suppose we wanted the ability to be able to add points together so for example if we take .1 plus .2 then we might get something like .12 and we might want to add points together by adding their x coordinates so negative 5 plus 15 would give us 10 and then adding our y coordinates so 10 plus 20 would give us 30 so our new point p12 would be at 10 and 30 so if we write in our code just to say print out the value of p1 plus p2 then we're going to get an error saying that we can't add points in other words when we tell python that we want to add these two point instances then python doesn't know how to actually take these instances and produce something that represents their values added together but we can override a method called underscore add underscore that will tell python how to actually add two points together so if we say def underscore add underscore so add is going to take in self but it's also going to take in what we're expecting to add to self so I'll call this other point for example when we print out the value of p1 plus p2 then p1 gets passed in for self and p2 gets passed in for other point now if we want to take the x coordinates and add them together and then take the y coordinates and add them together and return a new point then what we can say is we want to return a new point whose x is equal to self dot x plus other point dot x and whose y is equal to self dot y plus other point dot y and now as soon as we define this add method then when we print out the value of p1 plus p2 then we're going to see that we get a new point at 10 and 30 again this is just 15 plus negative 5 and 10 plus 20 gives us 30 beyond add there are several other methods that we could override so for example there's subtraction so for example if we wanted to be able to print out the value of p1 minus p2 then we could define this subtraction method and suppose that we wanted this to be defined as self dot x minus other point dot x self dot y minus other point dot y then now we have the ability to quote unquote subtract two points together there are many other methods that we can override but they follow the same pattern as add sub and they all start and end with underscores that's all for now until next time welcome back so you've already learned that functions and methods can return any kind of value as their return value but one thing that's worth noting is that they can specifically return other instances so let's suppose that we have this point class and this point class has a constructor and the constructor sets two instance variables for x and y and we have methods get x to return the x instance variable get y to return the y instance variable and then distance from origin to return how far x and y are from the origin suppose that we wanted to define a new method here suppose that we wanted the ability to accept two points and return a new point that was halfway between the two so for example here I have point p and I have point q and let's say that we wanted a function that would go return a new point that was halfway between point p and point q and let's call that function halfway and let's make it a method on every point so for example if I say p dot halfway when called with q then this should return a new point that is halfway between p and q so if I call this midway so I'll say mid equals p dot halfway q then I want this to return a new point and in this case the x should be halfway between 3 and 5 so the x should be 4 and the y should be halfway between 4 and 12 so the y should be 8 so let's define that method so I'm going to say def halfway like every method it accepts self and then I have a target and we want to return a new point that's halfway between self and target so I'll say the x so the mid x is equal to the average between self dot x and target dot x so self dot x plus target dot x divided by 2 mid y equals self dot y plus target dot y divided by 2 and I can return a new point return a point whose x is mx and whose y is mx and now if I print out what the value of mid is and run my code and I'll see that I get x equals 4 which is halfway between 3 and 5 and I'll see that y is 8 which is halfway between 4 and 12 and again note that mid is a new instance of my point class so I can do things like print out mid dot get x and I can print out mid dot get y and I'll get 4 and 8 respectively for those values that's all for now until next time welcome back so we've already seen that every instance of a class can have its own instance variables so for example here we have a point class and inside of the constructor to underscore init we can see that every point instance has instance variables for x and y to represent the position of that particular point now for example here when we create a new instance of point with x equal 2 y equal 3 then suppose that our point class is represented with this notation again so this represents our point class and p1 is an instance of the point class that has instance variable x set to 2 and instance variable y set to 3 now we also have another instance of our point class so that's p2 and p2 has x set to 3 and y set to 12 so we have p1 and we have p2 so one thing that I want to note is that instances have their own variables but classes can have their own class variables they work just like instance variables except that they belong to the class itself so for example here the point class has its own class variable called printedrep so I'm going to write that inside of the class point so I'll say printedrep is set to a star now the point class also has these methods which are also a form of class variables so we have underscore in it and its value is some function and we have this graph method whose value is a different function now whenever python searches for anything of the form instance name dot instance var so for example if we're doing p1.graph or p2.graph or even something like print p1.printed rep or print p1.x then the search order that the python evaluator goes in is it first searches inside of the instance so in this case if we're searching for p1.x then it searches inside of p1 and it finds x there and it evaluates that to b2 if it doesn't find an instance variable with the name x or in this case let's go with the example of p1.printedrep so if we're searching for p1.printedrep python first searches inside of the instance p1 it doesn't find it there so then it searches inside of the point class and that's where it finds it when we say p2.graph python first searches inside of p2 it doesn't find it there and so it searches inside of the point class where it finds it if we had something like print p1.z then python would first search inside of p1 it wouldn't find z there it wouldn't find z there it would then search inside of the point class it wouldn't find pz there either and so it would give us a runtime error now the way that we define this point class if I erase these annotations the way that we define the point class is that we have this graph method and what graph does is it kind of forms a text graph or a textual representation of a graph that contains this point so if I erase my annotations and I run my code so here I create two instances of point 1 at 2, 3, 1 at 12 and I call p1.graph and what that does is it creates a little textual representation where here you can see kind of an x-axis here you can see kind of a y-axis and I can see that my point p1 is at 2 so 2 and 3 and I can see that my point p2 is at 3 and 12 inside of this representation of graph I refer to self.printedrep so you'll note that here printedrep again is the class variable that's set to a star if I change printedrep to be let's say a lowercase x then you'll see that printedrep changes for both p1 and p2 when we actually call the graph method on both of them so that's an example of how classes can retain variables so again we have instance variables that belong to every particular instance and we have class variables which belong to a class here technically there are 3 class variables there's printedrep underscore init and graph that all belong to the point class that's all for now until next time welcome back before you write any code for classes there are a few questions that you should ask yourself first is what kind of data do you actually want to represent with your class is it a list of songs is it a list of students a list of cars etc and then once you know that then you should ask yourself what does one particular instance represent of this class so if it's a list of songs one particular instance might represent a song one particular instance of a list of students might represent one particular student then from there you should ask yourself what are the instance variables what's unique to every instance that you might have so if it's a list of students it might be something like a name a student ID if it's a list of songs it might be the artist the track name the length etc and then after you know that you should also ask what methods might you actually want so if every instance is a particular song then you might have a method for example to ping an external API to get the lyrics for that song if it's a student you might want to have a method to for example send a message to that student it depends again on what your instances represent then finally you should ask yourself what is a printed representation of an instance look like so if I print out a particular song then I might want to print out the track name and then the album name and maybe the length and you should have answers to all of these questions before you start writing code for classes now it's important to note that designing classes is really more of an art than a science and it's very common to also refactor or rewrite classes and instance variables and methods even for experts but all of this comes more with practice that's all for now until next time welcome back so I'm going to start by defining a class to represent a person so I'm going to say class person and let's say that every person has a name and a year that they were born so I'm going to create a constructor def underscore init that accepts a name and a year born and assigns instance variables for name and year born self.name equals name self.year born equals year born now let's suppose that I also want to have a method get age so get age that takes this year born and let's suppose that we have a current year so I'll define current year to be 2019 so get age is going to subtract current year so I'll say return current year minus self.year born and let's suppose that we also want to override the underscore str method so I'll say def underscore underscore to print out self.name so I'll use the dot format method and dot format self.name and self.get age okay so now we have a class to represent a person and every person has a name and a year that they were born so if I create something like alice equals a new person named alice smith and I print out the value of alice I also have to pass an year born so I'll just say 1990 whoops I need one more closing parenthesis here okay so now I can see that alice smith is the name and 29 is the age given that the year born is 1990 of course we're just going to ignore things like exact birthdays for this purpose now suppose that I wanted to define a new class to represent a student and what I want a student class to have is everything that a person has plus one more thing so I want students to have this notion of knowledge so what I'm going to do is I'm going to start by just copying and pasting my person class so I can do this and then let's suppose that I want to have another instance variable named knowledge which I'll start out as 0 so I'll say self.knowledge equals 0 and I want this to be student instead of person and let's suppose that I want to have this other method on student named study so deaf study and whenever a student studies then their knowledge should go up so I'll say self.knowledge plus equals 1 ok so now if I define Alice to be a student instead of just a person by saying Alice equals a new student then you can see that I still get Alice Smith age 29 if I print out Alice.knowledge then I should get 0 if I tell Alice to study and then print out Alice's knowledge level then I'm going to get 1 now this is a fine way of defining both a person class and a student class but there's a much easier and more concise way of actually doing this using something called inheritance the idea of inheritance is that you can define classes that inherit from other classes so in other words they take all of the instance variables all of the methods that that other class has and then they can add more instance variables and more methods so in this case every student is a person it's not true that necessarily every person is a student but every student is a person so what I'm going to do is I'm going to say that this student class should inherit from person so a student should have everything a person has plus more now the way that I say I want student to inherit from person is by putting parentheses after the class declaration here and putting the class that I want to inherit from inside of those parentheses so I'll say that every student is a person so now that I do this I can get rid of some of the repetitive parts of the student class so here for example get age is a little bit repetitive I need get age in both student and person because get age is already inside of person so I'm going to remove get age from the student class I'm going to do the same for the underscore str method and I'm going to do one more thing as well so this setting self.name and self.earborn is a little bit repetitive with the person class setting self.name and self.earborn so in the constructor for the student I'm going to say that I want to call the constructor this method of person and the way that I'll do that is I'll say person dot underscore init underscore and I'm going to pass in self.name and year.born now when I do this I'm going to call this init method or the person constructor on this new student so this is going to call this method and then this method is going to set instance variables for name and for year.born automatically so let's test this out with Alice and be sure that our code still works so you can see again we have our student Alice Smith born in 1990 and if I still run this code you can see that after Alice studies Alice's knowledge is 1 but now if I print out Alice dot get age you'll see that Alice is 29 if I print out Alice then you'll see that we get Alice Smith age 29 and the important part here is that even though Alice is a student and even though the student class didn't directly define underscore str or get age I'm able to call both of these methods on Alice because Alice is a student and student inherits from person and the person class has these methods get age and underscore str that's all for now until next time welcome back so we've already covered inheritance but it's worth talking about when we actually want to inherit and how we want to inherit at times so in general the way that python uses inheritance but let's suppose that we have a super class so I'm going to represent classes by this factory I think a factory is a good metaphor for classes a factory for constructing instances so let's say that this red factory represents a super class and a super class is the class that we're inheriting from let's suppose that this blue factory represents a subclass so the subclass inherits from the super class I'm going to represent that just by having this little red dot here and that's like a line representing that we remember that this subclass is inherited from that super class and then we of course have instances so you might have an instance and let's suppose that this instances of the subclass and I have this blue dot here to represent that python remembers that that instance is an instance of the subclass now whenever python is looking for any method or instance variables it's always first going to look in the instance so it's first going to look inside of the instance and it's going to ask does the instance have that thing if it doesn't then it's going to look inside of that instances class and it's going to ask does that instance class have that instance variable or method if it doesn't then going to look into the superclass and in python that's just how superclasses work by adding this extra layer of looking at the superclass for things that are missing in the subclass what we do is we inherit everything that the superclass has and more so this kind of gets to the question of when should we actually inherit from superclass well you should only inherit if your subclass should have absolutely everything that the superclass has plus more or maybe plus some small modification so let's go over an example of this so let's suppose that I want to represent books in the library and let's suppose that we have two kinds of books we have paper books and we have ebooks so the way that I would represent that in classes is I would have one superclass for book so I'd say class book and every book is going to have a title and an author so I'll say def underscore init and that's going to take in a title and an author and I'm just going to set self.title .title equals title self.author equals author and let's suppose that we have this underscore str method as well and we're going to return title by author ok so now I have this book class I can create a new book so I'll say my book equals a new book and let's suppose that the title is the odyssey and then if I print out my book then I'll see that my book is the odyssey by Homer let me actually add quotation marks on this when we print out the book title ok now let's suppose that a library can have two kinds of books let's suppose that it can have ebooks and paper books so both ebooks and paper books have everything that a book has plus more in the case of a paper book maybe we have a number of pages so I'll say class paper book inherits from book and I'm going to have a constructor that takes in a title author and num pages and then I'm going to call the book constructor so I'll say book.underscore init with self, title, and author then I'm going to assign an instance variable numpages so I'll say numpages equals numpages so that's a paper book now let's suppose that an electronic book doesn't have pages but it has a file size like 3 megabytes 5 megabytes hopefully not a gigabyte for a book but it has some size so I'll say class ebook inherits from book so just like a book an ebook is going to have a title and an author and I'll say underscore init underscore self, title, author and then instead of numpages it has size again that's going to be the number of megabytes that this ebook takes up so I'll say book.init with self, title, and author and I'll say self.size equals size okay so now let's say that my book is an ebook of the Odyssey by Homer and let's say that it's 2 megabytes so if I print out my book then I can see that it's still the Odyssey by Homer if I print out my book.size then I can see that it's 2 megabytes if this is instead a paper book so let's suppose that I also have a paper copy of this book my paper book equals new paper book the Odyssey by Homer and let's say that it has 500 pages then I can see that my paper book.size oops it doesn't have size instead it has numpages because paper books don't have a size they have num pages so you can see that my paper that numpages is 500 so in this example we wanted to create paper book and ebook as separate subclasses because in this case a paper book has everything that a book has so in this case a paper book has a title and an author and so does ebook so ebook has everything that a book has so it has title and author and paper book also has this additional thing numpages and ebook has this additional thing file size so that's when you want to inherit when you want to have a subclass that has everything that the superclass has plus more when you don't want to inherit is when you want to contain another class within a class so let's go through an example so let's suppose that I don't want these books to exist in isolation let's say that I want to have a library class and libraries are going to contain books so what I'm going to do is I'm going to say class library and every library has some fixed number of books so I'll represent that by saying def init self and I'm going to say that every library starts off with zero books so I'll say self.books is an empty list and then we can add books to our library catalog so I'll say def add self and then book and here book is going to be an instance of book so whether it's a book a paper book or an ebook what we do is we add that book to our list of books so I'll say self.books.append book and I'll say def get size this is going to return the number of books that we have so I'll return the length of self.books I'll actually give this a clear name get number of books ok so the important point that I want to highlight here is that even though there's some relationship between library and these book classes in that a library contains a list of books we didn't want to inherit from book or we didn't want book to inherit from library because it's not that a library has everything that a book has it doesn't or that a book has everything a library has it doesn't either it's just that libraries contain books so rather than inheriting from books I created a separate instance variable to actually contain this list of books that we have so this is an example of what's called composition so a library contains or is composed of a list of books but rather than inheriting from the book class then we want to have a list of books as our instance variable so let's see our class in action so let's suppose that I have the Ann Arbor district library a, d, l equals a new library and I say a, d, l dot add book my book and a, d, l dot add book my paper book now if I print out a, a d, l dot get num books then I'm going to see that my district library has two books that's all for now until next time welcome back sometimes when creating an inherited class you want to create a method that calls the superclasses method but just does a little bit extra now let me explain an example so let's suppose that I have this pet class and inside of this pet class I have a method feed to create something that inherited from the pet class let's suppose that I wanted to create a class dog so I'm just going to draw out the beginnings of that class dog and I want it to inherit from pet so I'll say pet in parentheses now let's suppose that whenever I fed my dog I wanted it to both call this feed method but then let's suppose that every dog instance also has a little extra message so let's suppose that a dog says arf thanks whenever a pet is called on that dog so if I did that feed itself if I did this and then let's say that I print out arf thanks so if I define my dog class this way whenever I create a new instance of dog and then call feed on that dog then all that happens is arf thanks gets printed out because when I define this feed method I'm overriding the feed method in the parent class so this would never get called at least not by default but there is a way to call it so the way to call the feed method for this pet class in addition to printing out this little extra bit of code that I wanted to run the way that I would do that is I would say pet so the name of the class and then I would say dot feed and I would call this on self now notice that this is calling feed on the pet class normally when we call feed we create a new instance so I might say d1 equals a new dog and normally I would say d1.feed and I would pass in no arguments here because d1 is an instance here instead I'm saying the name of the class directly so I'm saying pet.feed and since I haven't specified what instance to feed on and since I haven't specified which pet instance I'm calling feed on then I need to pass in the particular instance as the first argument to pet.feed if I tried to say something like self.feed here then self.feed is just going to refer to the dog's feed so again the way that I'll create a feed method on a subclass that has everything that the superclass's feed method has and more I'll call the superclass's feed method by saying the name of the superclass in this case pet and then I'll say whatever method I want to call and then I'll pass in the instance directly so in code this is what that might look like so here I have a dog class and the dog class inherits from pet but it has its own feed method inside of that feed method I first call pet.feed with whatever instance this feed method is being called on and then I print out our thanks after the pet.feed method has been called now this also works for constructors so let's suppose that I have another subclass of pet called bird and let's suppose that the bird class has its own constructor but I want to call the pet class's constructor as well well the way that I would do that is I would say pet.dunderscore in it and I would call it with whatever arguments I want to call so in this case I'll pass in self and then I'll pass in the name and what this is going to do is it's going to call the pet class's constructor on this new instance of bird so it's going to set name, hunger, boredom, and sounds so let's do some multiple choice questions okay so this question asks what would print when print out b1.sounds is run so b1 here is an instance of bird and if I'm calling b1.sounds then you'll see that that's an instance variable that gets set right here so here we're setting self.sounds equal to a copy of self.sounds by default every pet has a sounds list of you'll see that the bird class has a class variable set to chirp so when I call pet.dunderscore in it when it sets self.sounds equal to self.sounds a copy of self.sounds what that's going to do b1 is a bird is it's going to create a copy of this list of sounds and so b1.sounds ends up being chirp so again the reason that it's creating a copy of this list of sounds is because we have the super class pet is because we have the super class pet then we have a sub class bird so every bird is a pet and then we have an instance of bird and that instance is called b1 bird has its own value for sounds and pet has its own different value for sounds now when we say b1.sounds or self.sounds in the constructor equals a copy of self.sounds then python is going to first look for what is the value of self.sounds so let's go back to the constructor so when you said self.sounds here again self is b1 so we're setting self b1.sounds equal to b1.sounds and we're slicing it so that we create a copy of b1.sounds when python is searching for b1.sounds here it first searches inside of the instance this instance doesn't have a sounds instance variable yet and then it searches inside of that instance's class and so we find chirp or a list that only contains chirp as the list of sounds and so here we end up creating a copy of that so I mentioned all of that just to say that the answer to this is c let's do another question this question asks for the dog class defined in the earlier window what would happen when d1.feed is run if the pet.feed selfline was deleted so in other words if we deleted or commented out this line then what would happen when we called d1 which is a new instance of dog what would happen if we called d1.feed well so if this pet.feed selfline was deleted then the only thing in the dog feed method that actually runs is this print statement print arphthanks so remember that the pet.feed method is never called by default because this method overrides that method entirely so the only thing that would happen is print arphthanks would run so that means that the answer here is c that's all for now until next time welcome back we've created a special module that you can import test it's not available outside this runestone textbook environment in a full python environment you'd use a more sophisticated module probably one called unit test but this one's a little easier to use and understand we're just going to use one function in it called test equal and it takes two values as input if they're equal the test passes and if they're not equal the test fails so let's take a look here we're importing the test module and here we're invoking the test equal function from inside the test module it takes two inputs in this case the first input is an invocation of the square function and the second input is just the number 100 and when we run it it's going to tell us that the test passes it passes because square of 10 is 100 100 equals 100 if I were to change one of these values then the test would fail it expected to get 101 but it actually got 100 so the way that we usually do this is that we make the first value we pass in something that we're checking on and the second value is what it ought to equal so it expected to get something that equaled 101 but square of 10 didn't actually equal 101 and of course if I have this back at 100 and I do square of 9 instead that's also going to fail because it got 81 but it expected 100 now one thing that's important to understand about this test at test equal is that it's not creating errors if it fails the test the code execution will continue on so let's see that we have something else on the next line just another print statement when the test fails that doesn't mean that the execution will stop so it said that the test failed but it still went on to execute line 8 and print out the value 4 here's an instructive example we've got a function blanked it's actually not correctly implemented yet but we've looked at this before it's something that's going to be used in the hangman game a word that's the word to be guessed in the hangman game and some letters that have been guessed already and it's supposed to return a blanked version of the word and we're supposed to write a test that if we pass in the word under and d and u have been guessed already what we get back should be u blank d blank blank and in the code we have some examples of invoking test.test.equal our challenge is what's the right invocation that we'll check whether the blanked function when given under and d and u will return this so the correct answer is c and let's see why when we invoke the blanked function we have to give it two values the word under and the letters that have been already guessed and then we're checking whether what came back from the whole invocation of blanked whether that equals the u blank d blank blank b and a aren't quite right they don't have the syntax quite right in b we've sort of flipped we've got the values in the wrong place the blanked function takes a word and the letters that have been guessed so far we gave it the blanked version of the word instead of the letters that have been guessed already in a the problem is that we actually passed three different values to the blanked function and we didn't give a second value to the test.equal function so we just have this parenthesis in the wrong place so that's the mechanics of the test.equal function the test module you invoke it with two values and it checks whether those two values are equal. It's a way to check whether a variable has the right value or whether a function is returning the right value I'll see you next time welcome back we've already seen how to implement a test for a function you just invoke test.test.equal where the first input is an invocation of the function and the second input is the correct value the correct output for the function in this video we're going to consider what tests are good to implement and it's useful to distinguish between two kinds of things that a function might accomplish one is that it might return a value and the other thing is that it might have a side effect and by a side effect I mean that it might change the contents of a list or change the contents of a dictionary or it might also write to a file or produce some output in the output window but we're not going to use test.test.equal for checking on writing to a file or the output window but we will use test.test.equal to see if a list has been modified or a dictionary has been modified so I'll call the two different kinds of tests a return value test or a side effect test depending on what it is that the function was supposed to be doing let's first consider return value tests so this is a function like square where its whole job is just to compute a new value it gets an input, it produces an output it's not changing the contents of any list or dictionary so which inputs should we give it as tests and one way to think about that is to think about the equivalence classes of inputs because we're not going to be able to test every single possible input so maybe we should for something that's computing squares or some arithmetic thing maybe one equivalence class of inputs are positive numbers and you already see we've got one test where we're passing in three as an input but perhaps we ought to have another input which would be a negative number maybe if we somehow implemented this wrong it would work for the positive numbers but not work for the negative numbers so it would be a good idea to have a test of some negative value that if we square minus four we should get positive 16 and not negative 16 it's also a good idea to think of what other classes of inputs could we get maybe we could get a floating point number maybe it only works on integers for some reason so suppose I had two point to do something where I can actually compute it myself let's see one point five what's the square of one point five it should be two point two five I believe let's check that to be sure yes I've passed all three of those tests you'll notice this is an important point when you're writing a test you've got to figure out which inputs should you run a test on and you have to know what the correct output in that case I was a little unsure about the square of one point five but it is two point two five and then you also should think about sort of the boundaries between these equivalence classes so I did a positive number I did a negative number gee what happens if we do zero we'll get that right so it's a good idea to have a test for these boundary conditions these edge or extreme cases it's also helpful to think about what might go wrong like what could I possibly do wrong and this is a very simple function it's hard to think of things that could go wrong but maybe I did it with a plus instead of a times if I were to do test dot test equal square of two I would still get this right so I've failed most of my tests but square of two came out to be four even though I did it wrong and so two isn't really a great choice or if I do two I should also do something like three that would distinguish between a correct implementation and an incorrect implementation it's also worth thinking about return value tests for functions that have optional parameters if a function takes an optional parameter one of the edge cases to test for no parameter value is supplied during execution so let's consider the built-in sorted function you remember that it has an optional parameter reverse so I can call sorted of one seven and four and not specify any value for the reverse parameter it's optional and if I don't specify the reverse parameter at all I should get the results not reverse I should get one four and seven if I call sorted of one seven four with reverse equals true then I should get the values in the opposite order seven four and one so I should pass both of these tests now just to be complete I might want to have one more test here which is what happens if I call sorted on one seven and four but I say reverse equals false provided this parameter I should get the same value that I would get if I left out that parameter entirely and just got the default value because the default value is false so this one should pass as well but of course if I changed any of these seven one and four now I'm going to fail the second test instead we expected to get one four this is what we specified was supposed to be the value but we actually got seven four one now in this case we failed the test because I wrote a bad test the correct answer when we pass one seven four to sorted with reverse equals true the correct answer is seven four one and now we've passed it in summary you'll use a return value test when the purpose of a function is the correct output from its inputs you express the test by calling test dot test equal the first parameter is an invocation of the function the second is the correct output which you had to compute manually you should make one test case for each of the equivalence classes of inputs and don't forget the edge or extreme cases when you're dealing with a function that has optional parameters some of those edge or extreme cases should include omitting or including the optional parameters the art of creating test cases is that you're going to create several of them when you've correctly implemented the function that you're testing you will pass all of the tests but you want to have what's called good coverage of those tests they need to cover all the ways in which you might make a mistake in implementing the function so if there was some error in the implementation of the function then one of your tests ought to fail if it was correctly implemented it should pass all of the tests the order of this is to pick a good set of tests so that you'll fail if the function is not implemented correctly but you'll pass them all when the function is implemented correctly I'll see you next time welcome back here's a function that is supposed to have a side effect on one of its inputs the function is called update counts and it takes a function of letters and it takes a dictionary as input it's going to do some stuff it isn't returning any value so it's going to return none but it's going to have a side effect counts D is going to be changed it's going to be mutated somewhere in here on line 3 it's doing something on line 5 it's assigning to counts D and so if we want to check whether update counts is working correctly we need a side effect test to do a side effect test you're going to set up some known initial value for an object you're going to run the function and then you're going to see if that object is updated correctly so in our case we're going to create a dictionary on line 9 it's got two keys A and B we're going to call update counts on line 10 we're going to check on lines 12 and 14 two different tests to make sure that the counts dictionary has been updated correctly now what is update counts supposed to do well it's supposed to count all of the letters that appear in whatever string is passed into it like AAAB in this case we're passing in a string that has three A's and one B if there are three more A's then this A should become 6 and there's one more B so the B should become 3 and that's what you see is the test we check at the end is counts square bracket A equal to 6 and is counts square bracket B equal to 3 let's check whether the test is actually working turns out it's not working there are errors in there and we'll come back and we will fix all along here but before we do that let's think about other tests that we might want to have besides just the single tests that we have here where we have the original counts dictionary on line 9 and then we call update counts on line 10 what other initial dictionary might we want to try to pass into update counts and what other strings might we want to pass in so I have a couple of ways for you to think about how to decide which tests to run for a side effect test like this the first is just to think about edge cases what if we were to start with an initial counts dictionary that was empty then first going to get rid of all of our markings here so another possibility might be that we start with an empty dictionary and we call update counts and then we check something about what it should equal at the end counts square bracket A should now be three there weren't any A's in the dictionary we didn't have a count for A's we have three A's that we've passed in so we should now have a total of three so that's one possibility another edge case would be passing in an empty string so maybe we have the same counts dictionary that we had up here and now we're going to pass in to the update counts function an empty string and then we would want to do tests to make sure that the counts haven't changed so count square bracket B was two it should still be two because there weren't any characters in the string that we passed in some other possibilities you can imagine maybe we call update counts and we pass in a dictionary that has the same name as it does inside and then we would have some tests to make sure that counts D has been updated appropriately we could pass in a character string that includes letters that are not in the dictionary as we did already up here so that's one way to think about it it's just sort of ask yourself what are weird edge cases and another way to think about it is to kind of look at what will be in your code for update counts and think about exercising all the paths through that code so we're going to have a conditional if C is in the counts dictionary that's checking you know is this character C new so we ought to have two tests one for the possibility that a letter is in the dictionary already and another where the letter is not in the dictionary or we could include both in the same test a string that has the letter G in it as well as A's and B's the other thing is in our update counts there's going to be some iteration where we're going to go through all of the letters and so we're going to have some kind of for loop and an edge case for iteration is when you iterate through something that's empty so that's why it's a good idea to have some update counts where we pass in an empty string that's going to exercise a path through this for loop where we just skip everything inside the for loop alright so now we have a bunch of tests let's say after after I call this update counts I should have another check on test that test equal counts D square bracket A ought to equal 3 so if I run this we're going to find most of our tests have failed one of them passed that if we pass in a counts dictionary that's initially A has 3 and B has 2 and we update counts with an empty string we're still good counts of B is still 2 it didn't get mistakenly updated but we've failed most of our other tests so let's see what we would have to do to correct the code here so let's take a look at our first test we're passing in this dictionary A3 and B2 that's going to be the second parameter the first parameter is the string AAAB and we're expecting that A should be 6 but it's actually 2 so it starts with a value of 3 and it ends with a 2 and you can look in the code and you can see what's going wrong here is that when we first encounter the letter A so now the variable C is bound to the letter A we're setting the key A in the dictionary to have the value 1 so it used to have 3 but now it's getting set to 1 C is in the counts dictionary and then it's getting incremented to each time we encounter an A we keep resetting its count to be 1 so my problem is that I'm always setting counts D, square brackets C to equal 1 but I really should only do that in those cases where it's not already in the dictionary so this ought to be inside an else clause it should be conditionally executed now I think we're going to pass some more of the tests in fact that's sufficient to make it pass all of the tests so that's side effect test for you you create a side effect test whenever the function is supposed to make changes to a mutable object you set up an initial value for a variable, like I did on line 11 then you run the function like I did on line 12 and then you see if the object that the variable is bound to has been updated correctly that's what happens on lines 14 and 16 I'll see you next time welcome back testing a class definition involves creating instances and invoking methods on those instances here's a little class that lets us define points on an XY plane instead of just treating them as two numbers or making a tuple we're going to actually make an instance of a class each instance will represent one point with an attribute for its X position I'm going to draw a little grid again just so we have a place to plot our points so we can have a point like 3,4 which would be plotted there so to test our definition of this class we're really going to have to test the three methods that we have we have a constructor the underscore init we've got the distance from origin and we've got the move method let's start by doing the constructor because that's really the heart of any class how do we test if we've implemented this underscore init the constructor method how do we test if we've implemented it correctly to figure that out you've got to remember the mechanics of classes basically we create a new point by invoking the class when you create a point on line 19 you will create a new instance of the point class and then behind the scenes the constructor the init method will be called with 3 getting passed as init X 4 as init Y and the new instance itself will be bound to the self parameter now the purpose of the init method is to change the contents initially self has no attributes but after we've finished executing the init then self should have two attributes it should have an X attribute and a Y attribute and they should be bound to the corresponding values 3 and 4 that have been passed in so to test the class constructor we create a point and then we check whether it has its attributes correctly set is its Y attribute set to 4 is its X attribute set to 3 usually when we're doing a side effect test we would have to create an object like a list or a dictionary and then invoke a function and then see if the list or the dictionary has appropriately changed in this case we didn't have to do that because the invocation of the point class both creates the instance and invokes the method to one step but then afterwards we run our tests to see whether it came out right by the way if this is a little confusing for you because you're just coming from learning classes and the mechanics are a little hazy running this in code lens on your own would be really helpful to make sure you understand what's going on now the next method that I'm going to show you tests for is the distance from origin method and you can see that that distance from origin method what it's supposed to do is tell you how far away the point is from the origin in this case it's a distance of 5 if we picked some other point like 2,2 it would have a different distance but the 3,4 point should have a distance away of 2 this is a method that just returns a value it doesn't change the contents of the point so we should be doing a return value test and I'm just going to get rid of a few of these markings so testing the distance from origin method this is a return value test I still need to create a point in the first place I could have actually just used the P that I defined on line 19 but when I'm defining a test I like to see what's involved in the test right there so I'm recreating a new point P that's at position 3,4 and then I'm checking is it a distance 5 away from the origin then I should have some other tests as well I should make some different points that are different distances I could check whether a point at 2,0 is a distance 2 away from the origin and finally I've got this move method now with this move method what it's doing is taking a point like this 3,4 point and it's going to translate it it's going to make it move some distance so we'll pass into the move method a distance to move in the x direction and a distance to move in the y direction so in order to test that that is a method whose purpose is to have a side effect it's supposed to change the point and therefore I need to have a side effect test so I'm going to create tests here that again I create my initial point and then I move it so I'm moving it minus 2 in the x plane and by up 3 in the y so I'm going to go minus 2 from 3 over to 1 and plus 3 in the y so I should end up at 1,7 so in my test I'm checking so first I create the point then I move it and then I see if it has correctly been moved if my move method is correctly implemented the x value should be 1 and the y value should be 7 so in this case we'll run our tests we'll find out whether it's all correctly implemented it is correctly implemented if I had made some change or if some of these methods weren't defined yet then I would fail some of the tests the purpose again of having these tests is to check whether the implementation of the methods is correct if the methods have been implemented correctly you should pass all the tests if they haven't been implemented correctly then one or more of the tests will fail so that's a skeleton of how to test a class definition basically you need to assess for each method whether its purpose is to return a value or have a side effect testing the class constructor is special because each test will invoke the class with some parameters and then check whether the returned instance has its instance variable set correctly for the other methods you will also have to create an instance but then you invoke them and either check whether the return value is correct or check whether the instance has had its variables changed appropriately I'll see you next time welcome back writing automated test cases is a bit of an advanced topic for an intro programming course like this one we've included it because it's a preview of an essential software engineering practice for larger projects and it's a good idea to start developing the habit of testing right from the beginning of your programming career moreover the idea of edge cases is an important way to think about what your program needs to do indeed more generally you may find that the notion of edge cases influences how you think about processes beyond the realm of computer programming for example when I think about grading policies for my on-campus courses I like to think about edge cases what if a student gets sick the night before the assignment is due and then hands it in late what if a student skips some of the required assignments but then demonstrates mastery of the material by getting 100% on the exam those are edge cases that I need to have policies about I need to decide what is the correct grade to assign to students when those unusual circumstances occur learning to express your test cases as invocations of test.testequal is also a good way to reinforce your understanding the mechanics of functions and of classes at this point you should be able to use the test.testequal function to express test cases identify when a return value test is needed versus when a side effect test is needed and you should be able to identify and express edge cases for functions and for class definitions testing testing 1 2 3 testing is the mic working are we on camera? oh hi everyone that was just a little joke about testing that's all on testing for now bye everyone see you next time welcome back now remember that there are three main kinds of errors that we can get when writing python code there are syntactic errors that's when python doesn't understand how to read the instructions in your program so for example if I forget a bracket or parenthesis and I try to run my program then I get a syntax error saying that python didn't understand the instructions that I gave it beyond syntactic error there are also runtime errors runtime errors occur when python understood the instructions that I gave it but something went wrong when python tried to run those instructions so for example if I run my code right now I get a runtime error or more specifically an index error because even though python understands that I'm creating a list and assigning that list to items and then I'm assigning third to be the third item in items because item only has two items a and b when I try to fetch index 2 then I get an index error which is the kind of runtime error in other words python understood what I wanted to do but something went wrong as python was trying to execute my code and then finally there are semantic errors and a semantic error is when python successfully ran the code it just wasn't exactly what I wanted it to do so for example if I wrote a function to add two numbers and that function actually divided two numbers python isn't going to give me an error but I'm also not going to be happy when my code divides the numbers that I wanted to add so when we have a syntactic error python doesn't run our code at all when we have a runtime error python runs our code until it encounters the runtime error and when we have a semantic error python runs our code but it just doesn't end up being what we wanted it to be now usually when we encounter a runtime error then python is going to stop running our code as soon as we encounter the runtime error so for example this code again does an index error so let's suppose that I modified my code and I had something like print this is not going to be reached now if I save and run my code you'll notice that this line 3 doesn't print out because this expression results in a runtime error so again when you get a runtime error right here then our program just stops running and it goes in this case in index error if I had a print statement before this line printed then this would successfully execute so in this lesson we're going to learn about try accept what try accept does is it allows us to handle runtime errors and to tell python what to do when it encounters a runtime error so that it doesn't suddenly stop running your program every time it encounters one so let's say that I wanted to run the code after assigning third so let's suppose that again I have a print I want this to run statement and I want this line to print out even if I encounter a runtime error on line 2 the way that I can do that is by putting that into a try accept block so the simplest way to write a try accept block is just by saying try and then colon and then code inside of the try block and then I can write accept colon and then code that I want to run if some runtime error happens so let's suppose that if I get a runtime error while running line 4 let's suppose that I want to assign third to be false so I'll say accept third equals false but when I run my code it's not going to show us a runtime error anymore but instead I actually am able to reach this print statement even though I get a runtime error right here so to see what's happening I'm going to add a few more print statements so inside of this accept I'm going to print something went wrong and I'm going to add print a on line 4 and after assigning third I'm going to print out b when I run my code you'll notice that I have print a print a executes then when I set third equal to items 2 this gives us a runtime error and as a result of this runtime error print b you'll see never executes so what happens is as soon as I get a runtime error for any line in this try block Python jumps right to the accept block and starts running what's in the accept block so you'll see that something went wrong gets executed and then here we assign third to be false and then I want this to run gets executed after that now let's suppose that we didn't actually have a runtime error so I'm going to clear my output and I'm going to make it so that items actually does have three items now if I run my code then what happens is I never get a runtime error when assigning third because I actually have a third item here so a gets printed third gets assigned to c and then b gets printed and then we completely skipped the accept block because nothing went wrong and then we print out I want this to run so in brief what try accept does is it says try to run the code inside of this try block and if something goes wrong while you're running that code rather than stopping execution of the whole program just jump and run whatever is inside of the accept block if nothing goes wrong then we just skip the accept block entirely and run what's after the try accept that's all for now until next time hello and welcome to this addition to the way the programmer so my name is Charles Severance I teach Python courses web development courses and so I was tasked with giving you a real world example of object orientation and this is a little difficult for me because in the real world little tiny programs tend to not cause us as programmers to build or even use objects in a sophisticated way and so I've decided in this that I'm going to try to take you into a lot more complex world and give you a sense of what's going on behind the scenes and how object orientation is essential and so I'm going to actually use Django which Django is a web development framework and this is less about writing Django than it is about looking at how Django uses objects to interact with you as a programmer who's going to write Django so if you really want to go crazy on this go to my website dj4e.com which is under construction I'm not really teaching this course until a couple of months from now but this will be eventually by the time you're watching this maybe this will be far more sophisticated the thing I'm working through is what's called the Django tutorial and this comes from the Django community and this is where a lot of initial Django developers they just say hey you want to get started go ahead and get started and so we're going to go through like the first one and two but I've already done that and again this is not about Django this is about orientation so I'm going to play with these things and show you some of the source code so it might be good if I showed you the eventual source code that I'm trying to weave a narrative that we get to so let's take a look at that source code so if I go into polls 2 this is a little application it doesn't do much right now it just prints out hello oh I got to start the server hang on did you manage so I have the server running this is a little application now it's running okay so this is a little application that is only at the second step of the tutorial and the only thing that it does is print something out and as such it's not a very sophisticated application and I'm going to talk to you about three files the first file is a file called the urls file and the urls file is very simple and that it basically says for this particular path which is the path that has nothing here after that slash run this code from the file views with a method named index so if I look at views this is the view code and it basically is saying return an http response because this is part of the request response cycle hello world and that prints this thing out and it's calling a bunch of things believe me and I'll show you a little bit of how tough this would be if we didn't have Django doing all this work and so this is the code that we have to write and then there's the other thing that we're not going to cover too much about is how to create database tables and here's this models file and this class basically says let's make a question model which is also then a table in the database and then it is extending an object that comes from Django called models.model and if you look down this is the code that I've got to do and it has to create fields in the database and all these other things if I took a look at what this database is it ends up with all this other stuff and has all these files that are created for me there's data in these files and I mean there's a there's structure in these files etc etc and all I did was created this and so there's a sort of a very small amount of work that I had to do to sort of get Django to do a whole bunch of work for me and I do that by extending an object that I'm handed this models.model object is something that I'm extending so at the end of the day what I want to do is I want to look at what it takes to take a URL and have a piece of code that responds to that URL so here's some URLs I want to show you how Django works and what Django gives you in a way that makes building Django code way more easier than it could be so if I was to build a web server and I've written here and I'll show you this code in a second I've written sort of the simplest raw python web server that I could write and basically at some point a browser is going to type a URL it's going to send a request over the internet to your computer and in that computer there is like an operating system or a Mac or Windows or Linux and it has networking capability TCPIP and there are documents that if you really wanted to you can learn how to build those things you can type into Google RFC 791 or RFC 793 and then you can go get a sense of like how hard that really would be and I don't know if you played with sockets or not but there is some socket a socket library inside a python and then we're going to create a very simple web server that's going to sort of receive this request from the browser and then send back a really tiny little HTML bit that's going to be sent back to that browser very tiny HTML little body tag hello world slash body slash HTML and all of this stuff I'll cover all this stuff how we create this server and this just gives you this isn't even a real web server it's not reading files or anything else it responds to every request with hello world server and over and over again okay and then the next thing we're going to show after that is we're going to show how those three files that I showed you models.py, URLs.py and views.py we write 25 lines of code and then we've created this application that's very sophisticated and it's very capable and then after that I'm going to show you sort of the detail of how within Django Django creates objects that then you extend Django how you want your application to work so we're going to start with a very very low level concept of how a python program would talk directly to a web browser okay and so let's go take a look at first let's take a look at this server code let me start a new browser let me actually get rid of well the Django server can stay there cd.dot, cd.dot and you can download this from dj4e.com it's a little smaller so we can see it all okay so if you were here's some stack overflows that I used and some python documentation that I used to figure all this stuff out this is not particularly an object this is a socket library that's built into python already already and then if we take a look I have to put a tri-accept around all that stuff so we're going to call it we're going to print here's how you get at this thing we're going to call this to create server function and server socket we're telling it to start a socket a socket's a little different than a file it's kind of like a file handle except that it's a two-way thing which you can both read and write to the same thing it's you could write to a file because it's like two sides if you have one application and they're both connected via socket one side can write and then the other side can read and then the other side can write and it comes back and so it's like it's almost like two connections a socket is a bi-directional or a two-way connection so we're starting a socket this is the server side because in Django you're building the server side not a browser a browser is the client side this is the server side and we wrapped this whole thing in a tri-accept because I need to close these sockets if there's a if you're writing this code took me about an hour to write this code even after I found it on stack overflow so you don't really want to write this and I'm glad it worked you can look at it you can play with it but all it really it's whole goal of this code is to prove to you that you don't want to write this code and so I'll just walk through it what we're doing is we're going to be a server which means we are waiting for connections and that's what server socket.bind says wait for connection on port 9000 server socket.listen5 that means up to five connections and then this while loop basically says accept the socket if the socket has arrived so it will actually stop here until a socket connection happens so when a browser makes a connection to your server it sits here well it sits here until the browser makes a connection and then it drives down and it gets these two pieces of data which are a tuple but this is just an assignment statement right client socket address the address of where what the browser is coming from and the socket object so this is now client socket is an object that's populated by the statement so if you were to read the hdb protocol you would realize that the first thing the browser is going to do is send us a command like get or post with the url that it's interested in and so we're going to read the first 5000 characters from the browser and then we're going to decode it I'll split it based on new lines because it's actually a series of lines both the hdb command and then a series of header values and we're going to print the very first line which you're going to see how this works in a second and then we know what the hdb protocol is so we're going to just send back the simplest of httpages which is a 200 ok which says this is a valid document here you are we're going to send back a utf8 html and then a blank line so here's the blank line right here and then we're going to send the body with two new lines at the end and of course because we're sending it outside of our world we're going to do a data doting code so that the utf8 is properly sent so we're going to receive utf8 that's where this decode came in the get request that comes into us is going to be utf8 and then we're going to send back a document that's also utf8 that's also why I told it it's utf8 and then encode is what converts the unicode inside a python into utf8 and then we have to kind of shut it down which the shutdown sort of sends all the data make sure the data gets received and then takes the socket and then we go back up to the top and we wait for the next socket so that's each one of the URLs that gets retrieved is going to be handled and so if keyboard is if I hit control c or control z and it shuts down but closes the socket turns out it takes like a minute or two to be able to start it back up again unless you do it or if like you type in change in this you make a mistake you'll probably generate yourself an exception and we still want to close the socket if we made a mistake inside here that was really helpful for me because it took me a long time to get this code to work and it blew up a lot and so now it's not blowing up so now let's run this okay and I can see python 3 server dot py and now we have the world's simplest python server and so if I go into my browser and I go to local host local host 9000 that's the port it's like an extension on a phone system so local host colon 9000 says connect local host which is the same computer that I'm on this is not really leaving to the internet that would be a normal domain name colon 9000 says on 9000 and my Django was running on 8000 and my little mini python server is running on 9000 so I'm going to copy that I'm going to go into google chrome I'm going to turn on developer console and then I am going to turn watch the network and then I'm going to type in that URL that's just junk so we don't want that I don't want that doing so I'm going to hit enter all goes well yeah so it says hello world see that pretty awesome after all that work so what happens is if you go down here you can see that where is this I don't want to see yeah I don't want to see that so we sent a request to the local host on port 9000 we did a get 200 okay remember our application said 200 okay wherever that was see this little 200 right there 200 okay was the status that our browser got back from our application response headers response headers said that oh this is a html document with a character set of utf-8 oh looky looky looky we did that we said that in our in our python server dot py code and the request headers this is all that stuff this is the browser telling us what kind of browser it is etc etc and where that shows up is remember I did this split by only showing pieces of zero I'm not showing you any of those things but if you just were to print out this rd variable in your version of it you would actually see all of those headers and that's the HTTP request response cycle that's like the simplest version of the HTTP request response cycle now if we take a look at this we'll see that this is also retrieving the document favicon because it's trying to return the icon the icon that would show up right here and our our web server is not smart enough to give back icons it only says hello world to every single request because it went around twice it did this for the for localhost slash and then favicon it did it again and it simply sent back a document now after a while we could say oh this chart type is image jpeg and then we would have different body and then we could send favicons back and forth and if you'll notice that prints out at this print statement right here this print statement right here prints out the get request which is this is the first request that corresponds to that localhost this is the second request that corresponds to that favicon okay so we got two requests and now I'm going to blow this up and that's when it's going to hit the keyboard interrupt and then it's going to shut down and then it's going to finish that so that server.py was how a web application works but this is like such a tiny fraction if you really wanted to build a real live web application that had multiple files and css and images and all that stuff it gets harder and then there's parsing of the incoming data and if you google like the rfc for http rfc stands for request for comments you will find rfc2616 the hypertext transfer protocol that gives you some subset of how much information you need to know to write a web server to write a web browser and so I'll just start to skim down we got hundreds of pages that was just a table of contents goes down to 176 and this is one of many documents that describes how that works so it turns out that code that I wrote is not entirely compliant it's just barely good enough to do the most crude and simple version of this so that you can look at it and you can play with that, you can add print statements etc etc so if you were going to want to write an entire browser you have to figure all these things out right in Django like the 2616 hypertext transfer protocol you'd have to write all this there's all these other rules so I think what I'll do is I'll stop now and then coming back I'm going to show you how Django implements that exact same thing but then how your code hooks into Django in a way where you're using object-oriented programming to hook the code into Django in the right places so that the amount of code that you have to write is really small and the amount of documentation that you have to read is extremely small and then someone inside Django had to read lots and lots of things about how to make this stuff work so when we come back we'll talk a lot more about your relationship between the Django code and your code and how that relationship is done through object-oriented programming so welcome back now what I want to do is I want to dig into a little bit about how you as a developer of a Django application interact with Django itself with objects so just to recall if you're looking for the downloads djfree.com is the place to go we are working through the Django tutorial and I'm pretty much no further than part two in this particular one because I'm really not worried about building the Django app I'm really interested in how objects work so one of the things that you can do because Django is really cool open source is we're actually going to look at the source code to Django Django is open source and has 26,000 different separate modifications almost 1,700 contributors and it's a lot of source code it's probably a million lines of code and so this is real enterprise software it's very exciting stuff and open source is really cool because we can look inside Django Django is not a magical thing that we can't see and we can learn from it and understand it so what I'm going to try to do is I'm going to take you inside Django and our application that we write is going to be really simple it's this polls application that just prints out hello world because this isn't a Django class this is really kind of how object-oriented works inside Django so what we're doing here is if you read the Django documentation what you find is that oh okay there's this big thing called Django and you got to write these files this file urls that routes things and models that creates database tables and allows you to read and write data from those database tables and the views that shows what the user interface of this is and so you're supposed to create these files so I'm going to focus mostly on the models file and talk a little bit about what's going on inside of Django and how Django in effect creates classes and then you create classes that derive from the Django classes and then you can create objects that are based on your classes and then use those objects and so we're going to dig into the source code to Django and so this particular one let's take a look at this base.py the let me show you the models file that's our code so here's our models file and if you read the documentation in Django it says well if you want to create a database table it's called a model in the model view controller we're going to make a database table that has question text, publication date and then have some methods inside of it like how to print this particular object out as a string and then this was published recently is something that they're going to use and then we're going to have another table called choice and it's going to have a question column and a text column and we can see this there's this thing called migrations that reads this and it creates tables and so in here we have polls to choice question polls to choice which has those columns and it's created this database table for us all we did is we took this thing not only allows us during run time to read and write from the database but it also at setup time it creates things for us and so these two database tables here were created from this object because it runs one process to read through your objects then create database tables it's another process while it's doing request response cycles then it actually reads and writes the data in the database so that's one nice thing and so models.model is a class and if you just look at this we're creating a new class that's question it's our class and we're extending the models.model class and we're doing this to inherit lots and lots and lots of functionality and then the definition of this is just you know variables models.char field that's you know that's a variable or constant constant with some stuff and these are objects and all this stuff is kind of sitting there for us to sort of it almost creates a it's almost like a dialect of python that is specifically to define these database models okay so if you know that this is a class and that it's extending another class let's go find the source code to that class so now what we're going to do is we're going to go into the python github repository and here on line 383 in the base.py this big long thing if you're looking for it it's linked here from this slide right here and now this is Django code this is the code that was written by the Django project and so they made this model and if you look at this I mean you've made simple classes this is not that different than the classes you made right so you have an underscore underscore knit method in the first parameter itself now that should look familiar to you and then you have a couple of arguments and then we got a whole bunch of code and so if we start looking down here this is just the constructor so part of the goal of object-oriented programming is you get to write a little bit of code that leverages hundreds and hundreds of lines of code that somebody else some other really sharp people like let's see if we can find the contributors so this is a list of all the people that built this these people know a lot there's a whole bunch of people and we can see their work and what they're doing and how long they've been working and they're doing things like all these documents like the hypertext transport protocol and this and that and knowing how to talk to databases and when I talk to SQLite database and I talk to my SQL database and Postgres database and Oracle database you literally don't need to know anything and so what they're doing is they're building a really large object or class that then you can extend and you don't have to write all this code this is very general purpose code part of the goal of writing an object is to get this from you now we can look at it you shouldn't have to look at it you should be able to look at the documentation i.e. the documentation on these little tutorials I'm just trying to give you the sense that here we go and so this is still the constructor this is the initialization the constructor so now we now have a method so these are other methods and these are things that you'll sort of recognize the double underscore that's what happens when we convert a model object to a string underscore underscore so this is no different than if you convert a dictionary to a string there's a little method inside of Python that's double underscore string double underscore eq that's comparing equality hashing has to do with how dictionaries work get state set state and all these things are just the kind of things that if I am the Django developer I have to do this because that lets me mount my class into Django the right way and these are methods that would be documented like serializable value save and there's another like a whole bunch of stuff see how much we're going to save base if you're probably looking at the Django documentation to see all this stuff save parents we're still in the model object get an extra preview prepare database save clean validate unique so this is just code that was written by these people where are they all these people wrote all this code and read all the documentation and tested the heck out of it and you just write this code right here and you extend and you inherit all that stuff and that does things like creates all the tables which I showed you it actually hooks into an administrator interface let me see if I can show you that so this is an administration interface and so this user interface is part of your Django application that came from Django that's the admin tool the admin panel within Django and your model is now in there so you got some question text etc etc etc so all you did was created one little file right Django is this magical thing administrator interface, database creation, table creation etc etc you created this little file and away you go so then I'll show you one more thing just the pattern you'll see is kind of the same is in this views.py file so this is returning a response when you go here into the polls to application right it returns this response but if you were to look at this at the developer console under network you would see that there is a whole bunch of stuff that you've got to do to do HTTP we sort of saw that in the first video like the response headers all these things, what the content like is what the type is and there's many other things that might be necessary so you could learn how to write all these things or you could basically say I'm just going to inherit the obvious things and I'm going to return you can read the documentation on HTTP response so this is an object this is the constructor to that object and we're going to send in a string to the constructor so this HTTP response we could create it we could set headers we could do all kinds of things in it all kinds of other things that have to do with the HTTP protocol and so somewhere inside of Django they have to find this object that's the HTTP response so I can show us that one as well take a look at the HTTP response and we're using it in a very simple way but if you look inside Django you see there's a lot to it so here we go is content is a set of bytes in this case and that's the constructor then there's serialization etc and so all these things all those things are part of that object in HTTP response base if we go find that one which I think is just up here so even within this file they're using one class HTTP response base content type that's the thing about it's text slash html status that was the 200 ok etc care set utf-8 so we're setting that thing up that's a constructor here and if you were looking at the documentation you would see that the char setting the char set setting a cookie a cookie has to do with this little bit of data that goes back and forth between the server and the browser you don't have to know how to do that you can go read that RFC 2616 see if I got that look at 2616 and then we could search for cookie whoops how come I don't see that oh RFC RFC HTTP cookie which one is it maybe it's got its own document yeah there we go RFC 62 65 so if you want to set a cookie which is how we log in and out of applications you got to go read this one and how many pages is this it's only 37 pages but it turns out that thankfully somebody in the jango project where are we has a little come on has a method called set cookie for us so if you go look at the documentation if this HTTP response wanted to set a cookie back in the browser instead of reading all this stuff some kind person who helped write Django wrote this down and gave you a method called set cookie so I'll stop there I'm not really trying to get you to sort of be a wizard in any of this stuff I'm trying to give you a little tiny places where you can jump in and learn more the basic idea is there's lots of complexity to this lots of documentation lots of rules about how to comply to this stuff and Django has made it so that's all hidden behind this abstraction boundary you have objects you make those objects so we played with the models object and then we played with the HTTP response object and we can use as much or as little we didn't have to use the cookie in the response object we can use as much or as little of that stuff as we want and that's the beauty is that all that complicated detail is hidden inside Django with the convenience of we can use as little or as much of it as we want so I hope you didn't try to like write Django because of this I just wanted to make a little connection with how you work with large frameworks or large libraries and how object-oriented programing and the patterns of abstraction and hiding and inheritance can be put to good use both by building libraries and then by using those libraries I hope you found it useful cheers