Practice

classes and self

Let’s practice making a simple class. Open a new file and save it as class_example.py, we’ll be running this from the command line rather than the REPL. Pass in several variables and save them to the instance by using self:

class Vehicle:

    def __init__(self, make, model, fuel="gas"):
        self.make = make
        self.model = model
        self.fuel = fuel

daily_driver = Vehicle("Subaru", "Crosstrek")
# By default, this is how python represents our object:
print(daily_driver)

# The variables we saved to the instance are available like this:
print(f"I drive a {daily_driver.make} {daily_driver.model}. It runs on {daily_driver.fuel}.")
Here's what you should have seen on your command line:

class Variables

We can also add class variables - variables that exist for all instances of a class. Let’s add a variable called number_of_wheels to the class scope:

class Vehicle:

    number_of_wheels = 4

    def __init__(self, make, model, fuel="gas"):
        self.make = make
        self.model = model
        self.fuel = fuel

Let’s query both the instance and class variables. Note that we set the instance variable to 3, but the higher-level class variable is still set to 4.

daily_driver = Vehicle("Subaru", "Crosstrek")

daily_driver.number_of_wheels = 3

# Instance variables
print(f"I drive a {daily_driver.make} {daily_driver.model}. It runs on {daily_driver.fuel}.")
print(f"My {daily_driver.model} has {daily_driver.number_of_wheels} wheels.")

# Class variable
print(f"Most vehicles have {Vehicle.number_of_wheels} wheels.")
Here's what you should have seen on your command line:

Inheritance

Class inheritance in Python is super useful - you can easily create a hierarchy of classes to make your life easier and maximize code reuse. Let’s subclass our Vehicle class and extend it by breaking out Cars and Trucks.

class Vehicle:

    def __init__(self, make, model, fuel="gas"):
        self.make = make
        self.model = model
        self.fuel = fuel


class Car(Vehicle):

    number_of_wheels = 4


class Truck(Vehicle):

    number_of_wheels = 6

    def __init__(self, make, model, fuel="diesel"):
        super().__init__(make, model, fuel)

Note: we’ve moved the number_of_wheels variable to the subclasses. Our Car subclass sets this variable but instantiating a Car just passes through to Vehicle.__init__(). We do, however, provide a __init__() for Truck, which changes the default fuel to diesel and then calls super().__init__() which redirects to Vehicle.__init__(). This lets us make changes that are specific to Truck instances (but we can still call them Vehicles). Let’s instantiate our subclasses:

daily_driver = Car("Subaru", "Crosstrek")
print(f"I drive a {daily_driver.make} {daily_driver.model}. "
      f"It uses {daily_driver.fuel} and has {daily_driver.number_of_wheels} wheels.")

truck = Truck("Ford", "F350")
print(f"I also have a {truck.make} {truck.model}. "
      f"It uses {truck.fuel} and has {truck.number_of_wheels} wheels.")
Here's what you should have seen on your command line:

type, isinstance, and issubclass

The type() command tells us the type of an object - for example, a Truck or a Car. Note that it doesn’t know anything about inheritance, so you can’t use type() to check if a Car is a Vehicle. For that, we can use isinstance(). issubclass() is another useful function that we can use to see if a class (rather than an instance) is a subclass of another class. Add this to your code:

print(f"My daily driver is a {type(daily_driver)} and my truck is a {type(truck)}")

print(f"Is my daily driver a car? {isinstance(daily_driver, Car)}")
print(f"Is my truck a Vehicle? {isinstance(truck, Vehicle)}")
print(f"Is my truck a Car? {isinstance(truck, Car)}")

print(f"Is a Truck a subclass of Vehicle? {issubclass(Truck, Vehicle)}")
Here's what you should have seen on your command line: