Classes and type in python

Introduction

In this post we are going to discuss about Python classes and type.

We all know that Python is an object oriented language and here, everything is an object. Everything is an object and is descendant of a class. But what you might have not know is that every class is itself decendant of another class known as type.

This might be a little confusing to grasp and i hope the examples here will make it clearer for you.

In python we have the built-in type() function which lets you view the type of any object in python.

Let us consider the example below

name = "Mike"
print(type(name)) # <class 'str'>

We see that the type of the name is a string (ofcourse you knew that). No let us try building our own class.

We are going to build a class called Fruit and we are going to instantiate descendant fruits from our Fruit class.

class Fruit:
    def __init__(self, color, shape):
        self.color = color
        self.shape = shape

    def show_characteristics(self):
        characteristics = [self.shape, self.color]
        return characteristics

Fruits have a color, a shape and most of the time are sweet, so we are going to leave taste apart.

We know that we can instatiate a fruit from our fruit class and we have descendant.

Earlier i mentioned that even classes are descendant of another class above them. This means that strings, integers and even out fruit class has a supreme class above it.

The supreme class

When you inspect the time of an object like an instance of our Fruit or a string object like our name using the type() function, what it returns to you is the parent of that object. What will happen if we try to get the type of our Fruit class itself ?

Execute the code below

class Fruit:
    def __init__(self, color, shape):
        self.color = color
        self.shape = shape

    def show_characteristics(self):
        characteristics = [self.shape, self.color]
        return characteristics

print(type(Fruit))

What you get as output is . If you try to execute it on str, int and other python classes, you will get . Try executing it on the type too and you will get the same result.

This is because all classes and object inherit from the type class above everything else.

It is therefore possible to create classes in a less cleaner way than above.

We are going to re-create our fruit class directly from type.

Creating a class with type

If you look for type in the python help console, you see description of the arguments type takes in order to create a class.

It is worth noting that type takes either 1 or 3 arguments. When a single argument is passed, it will return the class from which the object inherits. When 3 arguments are passed, it returns to you a new class with the characteristics and attributes you pass in as last argument. More on that below

  • The first argument it takes is the name of the class you are creating.
  • The second argument is are the bases from which your class would inherit. Say you are creating a new class that inherits from str, then you will pass a tuple as second argument representing that
  • The third argument is a dictionary that will hold the methods and variables inside our class

Let us now create our class, We are going to recreate the same fruit class as above.

def fruit_init(self, shape, color):
    self.shape = shape
    self.color = color

def show_characteristics(self):
    characteristics = [self.color, self.shape]
    return characteristics

fruit_class = type("FruitClass", (), {"__init__": fruit_init, "show_characteristics": show_characteristics})

Let us explore what is happening here.

We are creating a class called FruitClass. It inherits from no other class (therefore the empty tuple). Our class has some methods like init and showcharacteristics which map to the functions we created above.

We created those functions above because it will be hard to fit into the dictionary but you could make use of lambda expressions there.

What we end up with is a class that we can use. Let us try it out

def fruit_init(self, shape, color):
    self.shape = shape
    self.color = color


def show_characteristics(self):
    characteristics = [self.color, self.shape]
    return characteristics


fruit_class = type("FruitClass", (), {
                   "__init__": fruit_init, "show_characteristics": show_characteristics})

orange = fruit_class("spherical", "orange")

print(orange.show_characteristics())

Running the code above will print ["spherical", "orange"] which means our class worked.

How is this useful ?

Having knowledge of the above underlying functioning in python will help you understand more in-depth the behaviour of objects and some classes in Python. With this, you can even define your own blueprints for creating other classes and types by just creating a class that inherits from the type class above.

This gives you power to be able to define your own behaviour for objects and even set rules on what happen when a new object is created.

We are going to end here for now and hopefully we will explore this more in-depth and practically next time. I leave it to you to experiment with this knowledge.