Python: Class and Object

An object in Python(and in general OOP) is a collection of data, and the behavior associated with the different aspects of the object.

Object-Oriented Programming(OOP) refers to, objects being the primary focus while programming and modeling all real-world entities as objects.

So when we analyze a problem, we need to identify 2 things-

The objects(entities) that can be constructed to represent all the elements(of the problem/use case).
How those objects(entities) will behave individually and with each other.

Class is the blueprint of an object. Class is the definition we write for building an object.

Let’s see how can we define a class in Python-

Define a Class

Here is the minimum example of a class that we can define. This is a class that represents a “Product”, and currently there is no property or behavior defined.

class Product:
    pass
Python

Let’s add some behavior to the product.

Here we have defined a method named “someMethod” that is responsible for doing something.

class Product:
    def someMethod(self):
        print("Some method called from the Product class")
        
        
my_product = Product()
my_product.someMethod()

print("Type: ", type(my_product))
print("Object id: ", id(my_product))
Python

Output:

Some method called from the Product class

Type:  <class '__main__.Product'>
Object id:  140079743073296
Plaintext

__init__

class Product:
    def __init__(self):
        print("Product class initiated")
        
    def someMethod(self):
        print("Some method called from the Product class")
        
        
my_product = Product()
my_product.someMethod()
Python

Output:

Product class initiated
Some method called from the Product class
Plaintext

WARNING

We dont need to pass the “self” parameter value while calling any method. Python will internally pass the “self” param value.

Attributes

Class attributes are used to store data inside an object. We can set an attribute to an object, just by using a dot notation.

Declare a class.
Create an object of the class.
Using dot(.) notation set the value of some attributes. Here we have set the value for attributes- “name”, and “price”.
class Product:
    pass

product = Product()

# Print attributes
print("Attributes after instantiation:", vars(product))

product.name = "BigBox Pro"
product.price = 99.99

print(product.name)
print(product.price)

# Print attributes
print("Attributes after setting:", vars(product))
Python

NOTE

It is not mandatory to declare the attributes in the class. We can set any attribute to an object after the object is created.

There are ways to restrict this behavior, which we have discussed later.

Output:

The values of the attributes are set, and we can access them after setting them.

Attributes after instantiation: {}

BigBox Pro
99.99

Attributes after setting: {'name': 'BigBox Pro', 'price': 99.99}
Plaintext

We can also access those attributes inside a class by using dot(.) notation on self.

class Product:
    def printDetails(self):
        print(f"Name: {self.name}") # this will fail if we do not set name attribute
        print(f"Price: {self.price}") # this will fail if we do not set price attribute

product = Product()

product.name = "BigBox Pro"
product.price = 99.99

product.printDetails()
Python

Output:

Name: BigBox Pro
Price: 99.99
Plaintext

The problem with setting attributes this way, is we don’t have full track of the attributes, and an attribute might or might not be set.

This behavior can be restricted by declaring which attributes would the object accept, by setting “__slots__” property. We just need to assign an array of the property name(as string), to the “__slots__”.

class Product:
    __slots__ = ['name', 'price']
    
    def printDetails(self):
        print(f"Name: {self.name}")
        print(f"Price: {self.price}")

product = Product()

product.name = "BigBox Pro"
product.price = 99.99
product.discount = 9.5

product.printDetails()
Python

Output:

We will not be able to set any attribute other than “name” and “price”, as we have declared only these attributes in the “__slots__”.

Setting any other attribute(like “discount” in this case) will throw an “AttributeError”.

Traceback (most recent call last):
  File "oop_example.py", line 12, in <module>
    product.discount = 9.5
AttributeError: 'Product' object has no attribute 'discount'
Plaintext

We can initiate the values in the __init__ method. Here we have 2 instance attributes “name” and “price”. We use these to store information related to the object.

class Product:
    def __init__(self)-> None:
        self.name = "Default product name"
        self.price = 10

product = Product()

# Print attributes
print("Attributes after instantiation:", vars(product))

product.name = "BigBox Pro"
product.price = 99.99

print(product.name)
print(product.price)

# Print attributes
print("Attributes after setting:", vars(product))
Python

Output:

Attributes after instantiation: {'name': 'Default product name', 'price': 10}

BigBox Pro
99.99

Attributes after setting: {'name': 'BigBox Pro', 'price': 99.99}
Plaintext

We can also pass the values to __init__ to set the attributes.

class Product:
    def __init__(self, name: str, price: float) -> None:
        self.name = name
        self.price = price

    def printDetails(self) -> None:
        print("Name:", self.name)
        print("Price:", self.price)


my_product = Product("Sonic Wireless Headphone", 99.99)
my_product.printDetails()
Python

Output:

Name: Sonic Wireless Headphone
Price: 99.99
Plaintext

We can also define class attributes, which are available in every object. These class attributes are shared in all objects of the class.

Class variables are defined directly in the class.
Class variables are accessed using dot(.) notation on the class name. Not through object(self).
class Product:
    # Class attribute
    # Shared for all object of the class
    obj_count: int = 0
    
    def __init__(self, name: str, price: float = 0):
        self.name = name
        self.price = price
        Product.obj_count += 1

product = Product("BigBox Pro", 99.99)

print(f'Name: {product.name}')
print(f'Price: {product.price}')
print(f'Product Object Count: {Product.obj_count}')


product2 = Product("Second product", 10)

print(f'Name: {product2.name}')
print(f'Price: {product2.price}')
print(f'Product Object Count: {Product.obj_count}')
Python

Output:

Name: BigBox Pro
Price: 99.99
Product Object Count: 1

Name: Second product
Price: 10
Product Object Count: 2
Plaintext

Methods

We have already seen the usage of methods. Methods are used to perform some tasks.

The method may or may not accept any parameter.

NOTE

Python supplies the first parameter of a method in the class, and the first parameter is a reference to the object(referenced by self) itself.

You can use any name in place of “self” but by convension “self” is used everywhere.

Object Comparison

import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2

# Example usage:
circle1 = Circle(5)
circle2 = Circle(10)
circle3 = Circle(5)


print(circle1 == circle2)
print(circle1 == circle3)
Python

Output:

False
False
Plaintext
MethodComparisonDescription
__eq__(self, other)obj1 == obj2equal to
__ne__(self, other)obj1 != obj2not equal to
__gt__(self, other)obj1 > obj2greater than
__ge__(self, other)obj1 >= obj2greater than or equal to
__lt__(self, other)obj1 < obj2less than
__le__(self, other)obj1 <= obj2less than or equal to
import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2
    
    # Check if equal
    def __eq__(self, other):
        return self.radius == other.radius

    # Check if not equal
    def __ne__(self, other):
        return self.radius != other.radius
        
    # Check if less than
    def __lt__(self, other):
        return self.radius < other.radius
        
    # Check if less than or equal
    def __le__(self, other):
        return self.radius <= other.radius
    
    # Check if greater than
    def __gt__(self, other):
        return self.radius > other.radius
        
    # Check if greater than or equal
    def __ge__(self, other):
        return self.radius >= other.radius

# Example usage:
circle1 = Circle(5)
circle2 = Circle(10)
circle3 = Circle(5)


print(circle1 == circle2)
print(circle1 == circle3)
print(circle1 != circle2)
print(circle1 < circle2)
print(circle1 <= circle2)
print(circle1 > circle2)
print(circle1 >= circle2)
Python

Output:

False
True
True
True
True
False
False
Plaintext

Object to String

Define method __str__() for the string representation of the object. Whenever we try to print the object the __str__() will be called.

import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2
    
    def __str__(self):
        return f"Circle with radius {self.radius}, has area {self.area():.2f}"

# Example usage:
circle1 = Circle(5)
circle2 = Circle(10)

print(circle1)
print(circle2)
Python

Output:

Circle with radius 5, has area 78.54

Circle with radius 10, has area 314.16
Plaintext

Or we can use __repr__() to represent the object. Purpose of __repr__ is to be clear, and generally used for debugging.

Use function repr() to print the output of __repr__().

import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2
    
    def __str__(self):
        return f"Circle with radius {self.radius}, has area {self.area():.2f}"
    
    def __repr__(self):
        return f"Circle({self.radius})\nArea: {self.area():.2f}"

# Example usage:
circle1 = Circle(5)

print(repr(circle1))
Python

Output:

Circle(5)
Area: 78.54
Plaintext

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.