 Just as we worked with built-in functions before we wrote our own functions, we've been using objects throughout the course. For example, when we create a turtle, it's an object. When we want to tell the turtle to turn left, we use dot notation and say t.left90, which tells the object t to use the left method with 90 as its argument. Strings are also objects. Let's create a string s and give it the contents a, b, c, d, e. Instead of having an uppercase function that we pass a string to, for example, new string equals upper of s, that's not how we do it. Instead, since s is an object, we say s.upper. And now if we look at new string, we have it all an uppercase. Lists are also objects. Let's create a list, 1, 2, 7, 5, 3, and then we can tell the list to sort itself, and then we can print it, and it's sorted into order. Those are the kinds of objects that we've been working with already. Now it's time to write our own objects. It seems like nobody understands objects, but everyone understands toasters, so let's write a class to simulate a toaster as a Python object. First, what's the difference between a class and an object? You can think of a class as a template or blueprint for what an object should look like, and an object as the thing that you build from the blueprint. Or you can think of a class as a cookie cutter and the objects as the cookies you cut out using the cutter. The diagrams in the book that show what objects look like aren't standard, so I'm going to just use a standard called uniform modeling language to draw diagrams of what our classes look like. The class name is at the top of the diagram. By convention, class names always begin with an uppercase letter. By convention means that this is an informal, possibly unwritten rule for the way most people write and are expected to write Python. You can go against convention, but people will look at you funny if you do so. In the UML diagram, you then list the attributes an object of that class should have. Attributes are like variables. They describe the things that an object has. In this case, a toaster has a number of slots, a voltage, 110 in the US, 220 in Europe. The browning level, usually 1 to 6. The number of slices of bread currently in the toaster, and a boolean that tells us whether the toaster is on or not. In a UML diagram, you give the data type of an attribute after the attribute name. The plus sign means that these are public attributes users can directly access or change them. Then, you list the methods of the class, the things that an object can do. If we had a robotic toaster, it could turn on, turn off, insert slices of bread, pop them out, and set the browning levels. Again, the plus signs mean that these methods are available to anyone using our class, and you specify the data types of the parameters and the method return values. Let's start writing this class in a file called toaster.py. We start out with the name of the class, class toaster, and then a constructor method with the special name of underscore underscore init underscore underscore. It takes one argument called self. Again, this is by convention. Self stands for the object we are building or working with right now. In this method, we set all the default values for our attributes. The number of slots for our self is 2. We'll set the default voltage to be 110. The browning level we'll set to 1. The number of slices in the toaster is 0, and is on will be set to false. We can now create a toaster object. Let's create a toaster object called bread burner, and the way you create a new object is to use the class name, and that calls the constructor. And let's print bread burner and see what that looks like. And that's our result. Well, that's not very helpful. We'll find a way to improve on that later. For now, we can examine the object by accessing its attributes. Let's print number of slots, and we're going to say bread burner dot n slots, and that will access the number of slots property, or attribute, that belongs to the bread burner object. Similarly, we can say print voltage, and then bread burner dot voltage. Let's set the voltage to 220. We can say bread burner dot voltage equals 220, and use it on the left-hand side of an equal sign to assign an attribute, and then let's print our new voltage, which will, again, access that attribute. Let's run this, and we have two slots, 110 before our change, and 220 volts after the change. There's nothing inherently wrong with our constructor, but if we want a four-slot 220-volt toaster, we have to manually reset the attributes. Instead, let's change our constructor and give it parameters so that we can create toasters with a particular voltage and number of slots. Since toasters should ship without bread in them, turned off, and the browning dial set to one, we can keep that part in the constructor. So in this case, my constructor will now say I want to have the self, I want to have a number of slots and a voltage when I build my toaster. The number of slots attribute that the object should have will be set equal to the number that I specified as my parameter, and the voltage of the object I am currently constructing will be the voltage that I specified in the parameter list. Now let's get rid of this preceding code, and this time I'm going to create two toasters. One of them will be a US toaster, and it'll be a toaster that has two slots at 110 volts, and I'm going to have a European toaster, which is a new toaster with four slots at 220 volts. Let's print the US toaster voltage just to make sure that it's correct, and let's also print the euro toaster voltage to make sure that those were set properly by our constructor, and there's our 110 and 220. It's still unsatisfying to have to print all the fields ourselves. It would be nice to be able to say print US toaster and print euro toaster and have the toaster object displayed as a string. We can tell Python how to convert an object to a string representation by supplying the underscore underscore str underscore underscore method so that you don't have to see me typing for a long time. I've typed this beforehand and just pasted it in. Here's our underscore underscore str str underscore underscore method. We create a string with placeholders and then use format to fill in all of the attributes of our object, and notice that we're using the if else shortcut to tell whether the toaster is on or off, and we'll return that result. Now, when we run the program, when we say print US toaster, US toaster an object. In fact, a toaster object will have to be converted to a string and this method will be called. Similarly, when we print the euro toaster object, the underscore underscore str underscore underscore method from the toaster class will be called and we get some very nice output indeed rather than what we used to get. And now we don't have to print every attribute individually, although if we want to print one of them individually, it's still possible to do so. Finally, we need to write the remaining methods. The turn on method sets the is on attribute of the object we're currently working with to true. The turn off method sets the is on attribute of our object to false. Insert bread needs the number of slices to insert. This if statement makes sure that we don't overfill the toaster. The pop bread method makes sure that the toaster is on before we prop any bread and no matter how much was in there, after we're done, there are no slices of bread in the toaster anymore. The set browning method gets a level and checks to make sure that the level is in range before setting the browning attribute of the current object. Here's how we call them. We create a toaster with two slots and 110 volts, we'll turn it on, and we'll insert bread and then print the result. Let's run that. We have two slots, 110 volts, two slices at browning level one and the toaster is currently on. Now wait a minute, you might be thinking to yourself, here's turn on. We called it and we gave no arguments, but here's turn on and it has one parameter. Similarly, when we called the insert bread method, we gave it one argument, the number two, but here in insert bread we have two parameters, self and an insert. What's going on here? And the answer is self. Remember, self refers to the object currently under consideration. In these two statements, what's really happening is this. The object that we specify at the left of the period, at the left of the dot, becomes the argument that fills in the self parameter. When we called the insert bread method, the object that we're calling it with becomes self and our other argument that's in the parentheses fills in the number of slices to insert into the toaster. Admittedly, this might seem slightly inconsistent, but that's the way the game is set up and we have to follow those rules. And that's the basics of creating and using objects. In the next video, we'll implement a class that lets us do operations with fractions.