[MUSIC] Python has several built-in data types like strings, lists and dictionaries. These types are very convenient, and they allow us to manipulate data as a unit, okay? And these types all have methods to them. So when you have a list, L, and you call L.append, append is actually a method even though we haven't called it that at this point in the class, all right? So these methods define behaviors on these data types or things that you can do to the data that's encapsulated inside the type. All right so each object has some data contained within it, and what we can do is defined by the methods that we have on that particular datatype. Now by itself, we could just use these built-in datatypes and create our own functions. And as we've seen, we can write some pretty interesting programs in Python. However, there's huge value in being able to define your own types. So object-oriented programming is centered around, well, objects. And what I can do is create new types for these objects. So if I define a new type, I can encapsulate some data inside that type, then I can define a bunch of methods that define the behaviors that you can perform on objects of that type. If we do this, we have additional power and flexibility in our programs, and you'll see that it can make a lot of things much simpler. So let's dive right in and see what one of these new types actually looks like. I'm defining a new type that I'm going to call Character here. So we're building some sort of game that has characters in it and I want to encapsulate information about each character inside its own type. Now, in Python, as in pretty much every other object oriented programming language, a type, when you define a new type, it's called a class. So in Python to do that, we first use the keyword class. We say this is a class. Then we give the name that we want that class to have, in this case it's Character, and by convention in Python class names always are capitalized. So you can see that I capitalized it. Furthermore, like everything else in Python, we've got a colon at the end. So don't forget the colon. All right, now after we've defined the class, we then can define a sequence of methods. And as I said, these are the behaviors that objects of this type will actually have. You'll notice that there are two interesting looking method names here, init and stir, and these methods look just like functions. The only reason that I'm not calling them functions is that they're defined inside the context of a class. So they can only operate on objects of this type Character, they can't be called directly in any other way. All right now the first special one is init, __init__. This is called an initializer. This is how we initialize objects of this type, all right? And this particular initializer takes three arguments, self, name and initial health. Now self is special, I'm going to explain that in a second, so let's ignore that. The two actual arguments that I'm sending in to create new objects of this type are name and initial health. Now I use that self variable. That self variable is actually a reference to the new object, and by convention in Python it's called self. Although you're not required to call it self, you should call it self, okay? All right, what I do now is I'm going to create some fields inside of the self object, and a field is referenced with this dot notation. So self.name, so this is the field name inside the object self, and I'm going to assign that the value of name. So this name here corresponds to the argument, name, up here. This name here is a field inside of the object self. I'm also going to then create a field, health, and have its initial value be the initial_health parameter that was passed to the constructor. And finally I'm going to define another field, inventory, and I'm just going to initialize that one to an empty list, all right? So when I create something of type Character, I pass it a name and initial_health, and self parameter actually gets sent in by magic. I'll discuss that a little bit more in a second, all right? And then I've initialized all the fields. Notice that I don't return anything. This init method is creating this new object self here and it doesn't need to return anything. Here's another special method, __stir__. Okay, this takes one argument and that argument is self. And this one you never call directly either. You don't have to call, these under bar, under bar methods get called behind your back by Phyton. And I'll show you code that uses it and actually gets them called. And in this case, when you call the stir methods, so if you say stir of an object that is of type Character, it will actually call this __stir method for you and it'll pass the actual object as self. And you can see that I'm building up a string s here. I'm creating a nice print-out of the information about the character and then I return that string. So the stir method should create a string and return it on all the classes that you define. Now I've got two additional methods, which I'm going to call these behaviors that I've been talking about, right? My character can grab things and my character can tell you what its health is, okay. And those are the only two behaviors. Now you might add a bunch of other behaviors if you're really building a game. You might have a drop behavior, or you might have an eat behavior, right? And eat increases your health, drop drops something out of your inventory, and so on, right. Grab takes this self parameter, just like all methods, and then it takes an item. This is the item that I'm going to grab. And all I do is I take the inventory field here self.inventory and I call a method on that. That's actually a list, which is basically another define type in Python, it just happens to be a built-in type, all right, that's already defined for us. I call .append here. That's the method on the list type that I passed the item object, okay? Get_health is even simpler, all right, all it does is return the self.health field, okay? So here I have now defined my class Character. Now I want to point out that I haven't talked about how I would use this class, and this is one of the beauties of object oriented programming. I can define this class without worrying about how other people are going to use it. I know that the only way that they can use it is by calling these methods that I've created, so I've defined an interface. And I know that you will obey the interface, so I don't have to worry about it. I know that you're not going to sneak in and decrement my health by 100 behind my back, right? I've given you no way to decrease the health of this character, therefore my health will always be at initial health. Okay, now that's silly in practice, but if I want to allow you to manipulate the health of the character I add methods that do so. Now I don't have to know anything about how you use it, I know that you'll use it the way that I intended it. Right, now I folded up this example here, okay I want to unfold it. This is the opposite side, this is using this class Character. So let's fold that up, okay, I don't care how it's defined. Well actually, let's just fold the methods up, okay. I don't care how the methods are implemented when I use the extraction. Okay, when I use lists I don't have to go and look at the implementation inside of Python of how append works. I just have to understand that there is an append method. Similarly, I just have to understand that characters have grab methods. I don't have to understand how it works in order to use it, all right? So here's how I actually create an object of my new type. The class name becomes the constructor. So when I want to create a new character, I call Character as if it were a function, and then I pass the argument's name and initial health. You'll see I don't pass self, all right? That gets handled behind my back. And that the init function, even though it didn't actually return anything, returns the new object that was created, okay. Here's how I call stir. If I use stir(me) it will behind my back call __stir__, and it'll pass the object me as self, right? Now I can grab a pencil and paper. Now this has gotta [LAUGH] be the most boring game you've ever seen if you're grabbing pencils and paper, but okay, right? I can print the thing again. Similarly I can call get_health. All right, and then it'll print that in my print statement. All right, so you can see here I created my character Bob with 20 health. I print out the string representation of him and you can see here's my string representation of my character Bob, right? Now I grab some items, I print it out again. You can see that my inventory has changed form being an empty list to being a list with my exciting pencil and paper items. You can also see that I can print out my health and you can see that my health is 20. So that's it. That's really the basics of defining and using your own classes to create types in Python. Now obviously doing this for real to build something that's more interesting then our simplistic Character class, adds a little bit of complexity. But really you just have to define these methods to create an interface that can be implemented by you as you build the class, and used by you when you use the class, all right? So we'll look at some more complicated examples throughout the week.