Python Classes and Objects

Python is an object-oriented programming language. The classes and objects are at the core of implementing object-oriented programming model in Python


What is a Python Class?

A class is a blueprint from which objects are created. The classes can have properties and functions.

For example, we can have a class Employee with employee_id as the property and work() as the function. We can create different Employee objects from this class.

The properties are generally at the object level, so the employee_id can be different for different Employee objects.

The functions are at the object level or the class level. These functions mostly work on object properties and perform specific tasks.


How to Create a Class in Python

We can create a Python class using the class reserved keyword. Let’s look at an empty class that doesn’t have any properties or functions.

class Employee:
    pass

Having an empty class doesn’t give us any benefits. So, let’s add some class properties and functions to it.

class Employee:
    employee_id = 0

    def work(self):
        print(f'{self.employee_id} is working')

How to instantiate a class in Python?

When we create a Python class, it automatically creates a default no-argument constructor for it. We can invoke this constructor to create the instance of the class. This instance is referred to as the object of the class.

emp = Employee()
print(type(emp))
emp.work()

Output:

<class '__main__.Employee'>
0 is working

The built-in type() function returns the type of the object. It’s used to get the Class information of an object.


What is the base class in Python?

Did you think how the Employee class automagically got a no-args constructor?

It’s because Python supports inheritance and every class in Python is automatically inherited from the base class “object”. When we don’t define a constructor for the class, the “object” class constructor is used to create the instance of the class.


Defining a Constructor for the Class

If you notice the Employee class implementation, there is no way to set the employee_id value. We can define a separate method to set the employee_id value. But, it’s the mandatory property of the Employee object. The best place to set these properties is through the constructor.

Python constructor is a special function that gets called when we create the instance of the class. This function name is always __init__ and it can have any number of parameters. The first parameter is always the object itself, usually named as the self variable.

Let’s go ahead and create a constructor for the Employee class. We expect the caller program to pass the employee_id value as an argument.

class Employee:

    def __init__(self, i):
        self.employee_id = i

    def work(self):
        print(f'{self.employee_id} is working')


emp = Employee(100)
emp.work()

Output: 100 is working

Note: The earlier code to create the Employee object will not work now because the Employee constructor is expecting an argument. If we call Employee(), it will raise TypeError: init() missing 1 required positional argument: ‘id’.


Can we have multiple constructors in Python?

Unlike other popular Object-oriented programming languages, Python doesn’t support method overloading and constructor overloading.

However, it won’t throw any error if we define multiple constructors in the class. The last constructor will overwrite the earlier defined constructor definition. Let’s look at it with an example.

class Employee:

    def __init__(self, id):
        self.employee_id = id
    
    # this will overwrite earlier defined constructor
    def __init__(self, id, n):  
        self.employee_id = id
        self.emp_name = n

    def work(self):
        print(f'{self.emp_name}[{self.employee_id}] is working')


emp = Employee(100, 'Pankaj')
emp.work()

emp = Employee(100)  # will raise Error
emp.work()

Output:

Pankaj[100] is working
Traceback (most recent call last):
  File "/Users/pankaj/Documents/PycharmProjects/AskPython/hello-world/class_examples.py", line 19, in <module>
    emp = Employee(100)
TypeError: __init__() missing 1 required positional argument: 'n'

Class Variables vs Instance Variables

When a variable is defined at the class level, it’s called a class variable. When the variable is defined in the constructor, it’s called an instance variable.

The class variables are shared across all the instances of the class whereas instance variables are unique to the instance. So, it’s very important to understand when to use the class variable and when to use the instance variable.

In the earlier examples, the employee_id attribute is unique to an Employee instance, so it’s better to have it as an instance variable and defined in the constructor.

Let’s say we want to keep a track on the number of employees instances created and the employee ids’ allocated. In this case, we can use class variables to store this data and updated by the instances.

class Employee:
    count = 0
    ids_list = []

    def __init__(self, i):
        self.id = i
        Employee.count += 1
        self.ids_list.append(i)


for x in range(0, 10):
    emp = Employee(x)

print(f'Number of employees created = {Employee.count}')
print(f'List of employee ids allocated = {Employee.ids_list}')

emp = Employee(1000)
print(f'List of employee ids allocated = {emp.ids_list}')

Output:

Python Class Object Example
Python Class Object Example
Number of employees created = 10
List of employee ids allocated = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
List of employee ids allocated = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1000]

Note: We can access class variables through the class name as well as the instance variable.


References: