Classes

This lesson will teach you how to create and use classes.

Object Oriented Programming



    Python is an object oriented programming language (OOP) which means that variables and functions that relate to the same unit are wrapped together as an object.

    In the previous lessons, you have used various functions on objects. For example, you used the lower() function to return the lowercase version of a string.

    In this lesson, you will learn how to create your own objects and use them.

    Consider a game program in which the player drives a car. You may have variables for the car such as:

    speed = 5

    color = “red”

    The player may also be able to perform actions while driving the car, such as these functions:

    go_forward()

    turn_left()

    turn_right()

    In OOP, you group these variables and functions into a single object and use dot notation to access them.

    car.speed = 5

    car.go_forward()

    In OOP, variables are typically called attributes and are used to define the information about an object. Functions are typically called methods and are used to define the behaviors of an object. While attributes are typically named as a noun (speed, color), methods are named as action verbs (go_forward, turn_left). Attributes are used to store information while methods are used to complete an action.

    When talking about objects, sometimes sources you read will use attributes and variables together, or functions and methods together. All attributes are variables, but not all variables are attributes. In the same way, all methods are functions, but not all functions are methods.

    Using OOP, it is simple to create multiple objects of the same type. For instance, you could have two cars which would have the same attributes and methods, but have different values for their attributes.

    car1.speed = 5

    car2.speed = 8

    Calling an attribute of one object has no effect on the other objects of the same class. For instance, using dot notation to call the method on car1 will make car1 go forwards, but will have no impact on car2.

    car1.go_forward()

    Wrapping functions and variables together into the methods and attributes of an object is known as encapsulation.

Create a Class



    A class is a way to create objects. Classes are like blueprints for the objects you want to make.

    To create a class, we use the keyword class. Add the

    class FirstClass:
      x = 5
                    

    This class is called FirstClass. It has one attribute; a variable called x with the value 5.

    It is common practice to capitalize class names by capitalizing the first letter of each word in the class name, and not use underscores.

Create an Object



    Now that we have a class, we can use it to initialize (create) an object. We call an object an instance of a class.

    To initialize an object, we call the constructor of the class. The constructor is a function with the same name as the class and automatically exists when a class is defined.

    class FirstClass:
      x = 5
    
    object1 = FirstClass()
                    

    Here we created an object of FirstClass and named it object1.

    We can then access the object's attributes using the dot operator. E.g. object1.x

    The code example below will print the value of object1's x attribute, which is 5.

    class FirstClass:
      x = 5
    
    object1 = FirstClass()
    print(object1.x)
    
    # Output:
    # 5
                    

    Now you will finally be able to run your code and return an output, because you are printing the the attribute x of the object object1

    You can also try to print out the object itself. However, the information you get back will only tell you some vague information about the object

    class FirstClass:
      x = 5
    
    object1 = FirstClass()
    print(object1)
    
    # Output:
    # <__main__.FirstClass object at 0x00000196E434A250>
                    

    When you run your code, the number code at the end may not match exactly the result you get. From this print statement, you can tell that this object exists, and the name of the class of the object. It also has information about the memory location of the object.

    If you want to get information about the attributes of an object, you have to remember to use dot notation to call the attributes that you want to print.

__init__() Function



    All classes automatically have an __init__ function that is called by the constructor at the moment an object is being initialized. We can override the default __init__() function to assign initial values to the attributes of the object, or to do any other tasks that should be done at the moment an object is created.

    You can delete the code for the FirstClass and replace it with the below code, since now we're going to create a more advanced class.

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    
    p1 = Person("John", 20)
    
    print(p1.name)
    print(p1.age)
    
    # Output:
    # 'John'
    # 20
                    

    The self parameter represents the instance of the class. We use self to access the attributes and methods of the object from within the class.

    We then pass in any attributes we want to initialize. E.g. name and age.

    Then we set these attributes using self and the dot operator. We can use the class to make different objects of the same type.

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    
    p1 = Person("John", 20)
    p2 = Person("Sam", 16)
    
    print(p1.name)
    print(p2.name)
    
    # Output:
    # 'John'
    # 'Sam'
                    

    Here we used the same class to create a second person with the name Sam and an age of 16.

    We just had to pass different arguments into the parameters, which then get passed to the __init__() method to initialize the objects.

    Again, self makes sure that the attributes are binded to that specific object being initialized and not another object.

Object Methods



    Objects can also contain methods. Methods in objects are functions that belong to the object.

    Let's create a method in the Person class that shows the person's name. Be sure that the function definition is indented so that it belongs to the Person class.

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    
      def show_name(self):
        print("Hello my name is " + self.name)
    
    p1 = Person("John", 20)
    
    p1.show_name()
    
    # Output:
    # 'Hello my name is John'
                    

    Again we use self to refer to the instance of the class. We can then use self to get the name attribute.

    You can also create methods that have additional parameters. For example, you can create a method that compares the object's age attribute with a number argument. Remember, for these methods you need to specify self as the first parameter if you want to get check the object's attributes inside of the method.

    However, like the __init__ methods, you do not need to pass in self as an argument when you use dot notation to call the method.

    In the below example, the method guess_age takes in a number and checks that number with the object's age attribute.

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    
      def show_name(self):
        print("Hello my name is " + self.name)
    
      def guess_age(self, other_age):
        if self.age > other_age:
          print(self.name + " is older than that")
        elif self.age < other_age: 
          print(self.name + " is younger than that")
        else:
          print("That is the age of " + self.name)
    
    p1 = Person("John", 20)
    
    p1.guess_age(18)
    p1.guess_age(21)
    p1.guess_age(20)
    
    # Output:
    # 'John is older than that'
    # 'John is younger than that'
    # 'That is the age of John'
                    


Modifying Attributes



    You can easily modify object attributes using the assignment operator (=).

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    	
      def show_name(self):
        print("Hello my name is " + self.name)
    
      def guess_age(self, other_age):
        if self.age > other_age:
          print(self.name + " is older than that")
        elif self.age < other_age: 
          print(self.name + " is younger than that")
        else:
          print("That is the age of " + self.name)
    
    p1 = Person("John", 20)
    
    p1.age = 25
    
    print(p1.age)
    
    # Output:
    # 25
                    

    You can delete object attributes by using the del keyword. Try out the below code to see the error message that you will see if you try to access an attribute on an object that does not exist. You might see this error in the code you write in the future if you accidentally mistype an attribute name.

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    
      def show_name(self):
        print("Hello my name is " + self.name)
    
      def guess_age(self, other_age):
        if self.age > other_age:
          print(self.name + " is older than that")
        elif self.age < other_age: 
          print(self.name + " is younger than that")
        else:
          print("That is the age of " + self.name)
    
    p1 = Person("John", 20)
    
    del p1.age
    
    print(p1.age)
    
    # If you run this code you will get an error because there is no age attribute on the object.
                  

    You can even delete whole objects by using the del keyword.

    class Person:
      def __init__(self, name, age):
        self.name = name
        self.age = age
    
      def show_name(self):
        print("Hello my name is " + self.name)
    
      def guess_age(self, other_age):
        if self.age > other_age:
          print(self.name + " is older than that")
        elif self.age < other_age: 
          print(self.name + " is younger than that")
        else:
          print("That is the age of " + self.name)
    
    p1 = Person("John", 20)
    
    print(p1)
    
    del p1
    
    print(p1)
    
    # If you run this code you will get an error because p1 is not defined (it doesn't exist).
                  

Challenges



    Easy Challenge: Animals

    Create a class called Animal that has two attributes, the animal's name and animal's sound, and one function called speak that will print out the animal's name and the sound it makes.

    Then, create a couple of different animal object variables for different types of animals. Below are some example results with three object variables: dog, cat, and bird.

    dog.speak() should print The dog says bark!

    cat.speak() should print The cat says meow!

    bird.speak() should print The bird says chirp!

    All three of these objects should be created from the same class.


    Difficult Challenge: Players at a tournament

    Imagine a lot of game players coming to a game tournament. In this example tournament, when one player plays against another, the result will be determined by their rank.

    For example, if you have a player1 who is rank 1 (the highest rank), and a player2 who is rank 200 (a lower rank)...

    player1.play_against(player2) should print Player 1 beats Player 2!

    If you want to make the results more interesting, you can add a random variable to the player's ranks when you compare them. That way, a player of a higher rank is more likely to win, but still may not win. (You can use random.randint(number1, number2) to get a random integer in a range from number1 to number2.)

    Once you have the players set up, put all your player objects in a list and use a for loop to have a player play against all the other players (make sure you add a check so they can't play against themselves!)