Classes in Python

by: George El., March 2019, Reading time: 6 minutes

In this post I will explain what classes are and then I will show you how to create instance methods and class methods and what is the difference between them. Then I will also show you how to create static methods.

What are classes? Classes are blueprints that represent real life objects. For instance, lets say we want to represent a car. A car has some properties or attributes like color, brand, engine, doors, lights, etc and it can also do some actions like start, stop, accelerate, break. These actions are called methods. To represent a car we will define a class named Car. The simplest class is the following

class Car:
    pass

We will add the attributes and methods later. I want to show you first how we can create an object or an instance of this class. In other languages we use the “new” keyword to create an object of the class, but in python we instantiate an object using “classname()”. Then we can assign some attributes to this object using the dot “.” notation. For example, to create an instance of the Car class we use Car()

>>> mycar = Car()
>>> mycar.color="blue"
>>> mycar.brand="VW"

and I can do also anothercar

>>> anotherCar = Car()
>>> anotherCar.color="white"
>>> anotherCar.brand="toyota"

Each car has its own attributes. Instead of writing the attributes afterwards, it is common practice to pass these attributes when we instantiate the object. In order to do that we define a special method called __init__.

class Car:
    def __init__(self, color, brand, num_doors):
        self.color = color 
        self.brand = brand
        self.numDoors = num_doors

“self” is also a special keyword, it means this object. Other languages use the “this” keyword instead of “self”. So now we can instantiate an object like this:

mycar = Car("blue","VW", 4)
yourcar = Car("white, "toyota", 5)

and I can access these attributes using mycar.color, mycar.brand, mycar.numdoors

Instance Methods

We can also add some methods. These are nothing but normal functions that have access to object data. You will notice that they get the self keyword as argument and they can also get other parameters as arguments. The self keyword allows them to access instance variables.

class Car:
    def __init__(self, color, brand, numDoors):
        self.color = color 
        self.brand = brand
        self.type = numDoors

    def start(self):
        print ("car started")

    def stop(self):
        print ("car stopped")

    def accelerate(self):
        print("accelerate")

    def deaccelerate(self):
        print("accelerate")

we can call these methods after we instantiate an object like this

mycar = Car("white","toyota",5)
mycar.start()
mycar.stop()
...

I can also create another special method __str__ that returns a string representation of the object. This will be called each time I print an object of this class. Lets add it

class Car:
    def __init__(self, color, brand, numdoors):
        self.color = color 
        self.brand = brand
        self.numdoors = numdoors

    def __str__(self):
        return f'{self.color},{self.brand},{self.numdoors}'

    def start(self):
        print ("car started")

    def stop(self):
        print ("car stopped")

    def accelerate(self):
        print("accelerate")

    def deaccelerate(self):
        print("accelerate")

If I create an object and execute the following methods I will get

mycar = Car("white","VW",5)
print(mycar)
white, VW, 5
mycar.start()
car started
mycar.accelerate()
accelerate
mycar.stop()
car stopped

Now we will modify the accelerate method to get a parameter, speed, and we also initialize it to 0 in the __init__ method. I will also add a method current_speed that will print the current speed.

class Car:

    def __init__(self, color, brand, numdoors):
        self.color = color 
        self.brand = brand
        self.numdoors = numdoors
        self.speed = 0

    def __str__(self):
        return f'{self.color},{self.brand},{self.numdoors}'

    def start(self):
        print ("car started")

    def stop(self):
        print ("car stopped")

    def accelerate(self, speed):
        self.speed += speed
        print("accelerated "+str(speed)+" mph")

    def current_speed(self):
        print("current speed of "+str(self)+" is ",self.speed)

    def deaccelerate(self):
        print("deaccelerate")

Lets call this method now

mycar = Car("white","VW",5)
mycar.accelerate(10)
mycar.accelerate(15)
mycar.current_speed()
mycar2 = Car("yellow","toyota",5)
mycar2.accelerate(20)
mycar2.current_speed()

the output is

accelerated 10 mph
accelerated 15 mph
current speed of white,VW,5 is  25
accelerated 20 mph
current speed of yellow,toyota,5 is  20

Instance vs Class variables and methods

all these variables or attributes that we have seen so far are called instance variables because they are related to an instance of the class. But we have have also variables and methods that are related to the class and not to the objects of this class. For instance I can have a variable that stores the total number of cars created and a method that prints the total number of cars. These are called class methods and class variables. Lets go ahead and create a class variable called total that will store the total number of cars created. We will also create a class method total_num_of_cars that will return the total number of cars created.

class Car:
    total = 0
    def __init__(self, color, brand, numdoors):
        self.color = color 
        self.brand = brand
        self.numdoors = numdoors
        self.speed = 0
        Car.total+=1

    def __str__(self):
        return f'{self.color},{self.brand},{self.numdoors}'

    def start(self):
        print ("car started")

    def stop(self):
        print ("car stopped")

    def accelerate(self, speed):
        self.speed = speed
        print("accelerated "+str(speed)+" mph")

    def deaccelerate(self):
        print("deaccelerate")

    @classmethod
    def total_num_of_cars(cls):
        print('total num of cars =', cls.total)

In the __init__ method I access the class variable total with Car.total. If I try to access it like that total+=1 I will get an error “local variable ‘total’ referenced before assignment”. Also if I do self.total+=1 it will create an instance variable called total, and will not affect the class variable total. However, accessing this class variable from an object is allowed.

Please note we use the @classmethod decorator to create a class method. We also pass the “cls” instead of “self” keyword to denote a class.

If I create two cars and call the class method I will get two. Please note, I can call the class method either using the Class name Car, or the object, however since it is a class variable it is better to call it using the class Car.total_num_of_cars()

mycar = Car("white","VW",5)
mycar2 = Car("white","VW2",5)
Car.total_num_of_cars()
total num of cars= 2
mycar.total_num_of_cars()
total num of cars= 2

Static Methods

The third type of methods, staticmethods are marked with @staticmethod decorator. They take neither a self nor a cls parameter so they can neither modify object state nor class state. For example we could have a static method that converts mph to kmph

@staticmethod
def mph_to_kmph(mph):
    print("kmph = ", mph*1.6 )

I can call this method and will print

mycar.mph_to_kmph(25)
kmph =  40.0

So now the whole program looks as following

class Car:
    total=0
    def __init__(self, color, brand, numdoors):
        self.color = color 
        self.brand = brand
        self.numdoors = numdoors
        self.speed = 0
        Car.total+=1

    def __str__(self):
        return f'{self.color},{self.brand},{self.numdoors}'

    def start(self):
        print ("car started")

    def stop(self):
        print ("car stopped")

    def accelerate(self, speed):
        self.speed += speed
        print("accelerated "+str(speed)+" mph")

    def current_speed(self):
        print("current speed of "+str(self)+" is ",self.speed)

    def deaccelerate(self):
        print("deaccelerate")

    @classmethod
    def total_num_of_cars(cls):
        print('total num of cars =', cls.total)

    @staticmethod
    def mph_to_kmph(mph):
        print("kmph = ", mph*1.6 )

Summary

We covered a lot. We saw

  • how we can define a class
  • how we can create an instance or object of this class
  • how we can define instance, class and static methods

But there is lot more. For instance, in reality, you would not instantiate the car class, but you would define it as an abstract class. Then you would create subclasses of this abstract class. In another post I will show you how to do this.

comments powered by Disqus