class and object

Python Class and Object

February 03, 20247 min read

Classes in Python are essentially blueprints for creating objects. They encapsulate data for the object and methods to manipulate that data.

To understand classes, imagine a class as the architectural plan for a building. This plan outlines the structure of the building, including all its components like rooms, doors, and windows. Just as a building is constructed based on its plan, in Python, an object is an instance of a class, built according to the class's blueprint.

In Python, we use the class keyword to define a class. Consider the example below where we define a class Vehicle:

class Vehicle:
    # class definition

In this case, Vehicle is the name of the class.

Let's explore this concept further with a specific example:

class Car:
    model = ""
    year = 0

Here, Car is the class name, and model and year are attributes with default values "" (an empty string) and 0, respectively. Attributes in a class are akin to properties or characteristics of the class.

When we talk about objects in Python, we refer to them as instances of a class. For instance, if Car is a class, we can create objects like car1, car2, etc., from this class. The syntax for creating an object is:

objectName = ClassName()

For example:

# create class
class Car:
    model = ""
    year = 0

# create objects of class
car1 = Car()

In this example, car1 is an object or instance of the Car class. We can use this object to access and manipulate the class's attributes.

To interact with class attributes, we use dot notation. For instance:

# modify the model property
car1.model = "Sedan"

# access the year property
car1.year = 2019

Here, we've used car1.model and car1.year to update and access the model and year attributes, respectively.

Let's consider a more comprehensive example to illustrate these concepts:

Example 1: Python Class and Objects

# define a class
class Car:
    model = ""
    year = 0

# create object of class
car1 = Car()

# access attributes and assign new values
car1.year = 2019
car1.model = "Sedan"

print(f"Model: {car1.model}, Year: {car1.year}")

Output:

Model: Sedan, Year: 2019

In this example, we've defined a class named Car with two attributes: model and year. We've then created an object car1 of the Car class and accessed and modified its properties using dot notation.

We can also create multiple objects from a single class. For instance:

# define a class
class Worker:
    # define a property
    worker_id = 0

# create two objects of the Worker class
worker1 = Worker()
worker2 = Worker()

# access property using worker1
worker1.worker_id = 3001
print(f"Worker ID: {worker1.worker_id}")

# access properties using worker2
worker2.worker_id = 3002
print(f"Worker ID: {worker2.worker_id}")

Output:

Worker ID: 3001
Worker ID: 3002

In this scenario, we've created two distinct objects worker1 and worker2 from the Worker class and assigned unique worker_ids to each.

Methods in Python are functions defined inside a class. They are used to define the behaviors of an object. For instance:

# create a class
class Room:
    length = 0.0
    width = 0.0
    
    # method to calculate area
    def calculate_area(self):
        return self.length * self.width

# create object of Room class
living_room = Room()

# assign values to properties
living_room.length = 20.0
living_room.width = 15.0

# access method inside class to calculate area
area = living_room.calculate_area()
print(f"Area of Living Room: {area}")

Output:

Area of Living Room: 300.0

In this example, the Room class has two attributes (length and width) and a method calculate_area which computes the area of the room. We created an object living_room, assigned values to its attributes, and called its calculate_area method to calculate and print the area.

Constructors:

Constructors in Python are special methods used to initialize new objects. They are defined by the __init__() method. Here's how you can use a constructor in Python:

class Car:
    
    # constructor function    
    def __init__(self, model = "", year = 0):
        self.model = model
        self.year = year

car1 = Car("Sedan", 2019)

Here, __init__() is the constructor function that's automatically invoked when a new object of the Car class is created. This constructor initializes the model and year attributes of the object.

This example demonstrates how a constructor can set the initial state of a new object, allowing us to create objects with predefined attributes.

Self:

The self keyword in Python can be likened to a personal pronoun in human languages like "I" or "myself." It's used within a class to refer to the instance of the class itself. It helps differentiate between the instance’s attributes and methods from those of other instances or the class itself.

Let's use an analogy of a classroom to explain the concept of self. Imagine a classroom where each student can speak about themselves - their own name, their own grades, and their own belongings.

  1. Classroom (Class): The classroom is like the class in Python. It's the blueprint that defines the structure and behavior of the students (objects) within it.

  2. Students (Objects): Each student in the classroom is like an object in Python, created from the blueprint of the classroom (class). Every student has their own attributes (name, grades, etc.) just like objects have attributes (variables).

  3. Referring to Oneself (Self): When a student talks about themselves, they refer to themselves as "I" or "me." This self-reference is crucial because it distinguishes their identity from that of other students. In Python, self serves a similar purpose. Inside a class, when an object wants to refer to its own attributes or methods, it uses self.

For example, if a student named Alice wants to talk about her grades, she doesn't just say "grades" (which could be anyone's grades in the classroom). Instead, she says "my grades," clearly indicating that she's talking about her own grades, not someone else's.

Similarly, in Python:

class Student:
    def __init__(self, name, grades):
        self.name = name  # Here, 'self' ensures 'name' is associated with the specific instance.
        self.grades = grades  # Similarly, 'self.grades' refers to the 'grades' of the specific instance.
    
    def introduce(self):
        print(f"My name is {self.name} and my grades are {self.grades}.")  # 'self' refers to the specific object calling this method.

When we create an instance of Student:

alice = Student("Alice", 92)

And when alice calls the introduce method:

alice.introduce()

The self in the introduce method knows it's referring to the alice instance of Student. So, it correctly accesses Alice's name and grades, and not someone else's. Without self, Python wouldn't know which specific object's name and grades you're referring to, similar to how saying just "grades" in the classroom wouldn't be specific enough.

__STR__ method:

The __str__ method in Python is akin to giving an object the ability to understand and represent itself as a string in a human-readable form. It's one of the special or "dunder" (double underscore) methods in Python, intended to provide a meaningful string representation of an instance of a class.

Imagine you have a robot. This robot can perform various tasks, but you also want it to be able to introduce itself and describe what it is in a way that's understandable to humans. The __str__ method is like programming this self-description into the robot.

Here's a more detailed breakdown:

  1. Purpose: The __str__ method is called when you use the print() function on an object or when you use the str() function to convert an object to a string. The method should return a string representation of the object.

  2. Human-Readable: The string returned by __str__ is intended to be human-readable. It should provide a description of the object that makes sense to someone reading it.

  3. Customization: Without a custom __str__ method, the default string representation provided by Python for an object isn't very informative (it's usually something like <__main__.MyClass object at 0x000002C572F6E400>). By defining your own __str__ method, you can provide a much more useful and readable description.

Let's see an example to illustrate this:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def __str__(self):
        return f"{self.year} {self.make} {self.model}"

# Create a new car instance
my_car = Car("Tesla", "Model Y", 2021)

# Print the car object
print(my_car)

Output:

2021 Tesla Model Y

In this example:

  • We define a Car class with attributes for make, model, and year.

  • We define the __str__ method to return a formatted string that provides a human-readable description of a Car instance.

  • When we print my_car, Python automatically calls the __str__ method, which returns "2021 Tesla Model Y".

Without the __str__ method, printing my_car would give you something less informative, like <__main__.Car object at 0x000002C572F6E400>. With __str__, you get a meaningful description of the car, making your code more readable and your objects more understandable.

blog author image

sunil s

Quant Developer & Mentor

Back to Blog