Classes and Objects in Python – Explained with Examples
Basics of Python
5 Hrs. duration
9 Modules
1800+ Learners
Start Learning
In the world of Object-Oriented Programming (OOP), it is considered the most efficient approach for creating flexible, modular, and extensible software systems. No matter how simple a script is or how complex a software application gets, it’s the concepts of classes and objects that one must learn to create better software.
This article covers these important subjects providing guidelines on creating and using classes and objects. We will learn about the advanced OOP concepts used in classes such as inheritance, encapsulation, abstraction, and polymorphism that enhance flexibility, and maintenance of the code base. OOP concepts will be thoroughly understood within the framework of the Python programming language and you will look at the principles of operation with real practical examples and the ways of optimal code writing.
What is Object-Oriented Programming (OOP)?
Object-Oriented Programming (OOP) means modelling real-world entities as objects where each object is an instance of a class. In this way, methodology aids in modelling large codebases by mirroring the real world. In other words, object-oriented programming is a method for simulating tangible, real-world objects like vehicles and the relationships between them, such as those between employers and employees or between students and teachers. OOP models real-world entities as software objects with data associated with them and operational capabilities.
Key Concepts of OOP:
Encapsulation: The class and the included data (attributes), and methods (functions) that operate on that data are bundled together.
Inheritance: It is about new classes with attributes and methods from existing classes, enhancing code reusability.
Polymorphism: It is the ability to allow objects of different classes to be treated as objects from a common superclass (usually achieved through method overriding).
Abstraction: Hiding the internal implementation details and exposing only the necessary functionalities.
What is a Class in Python?
In Python, a class is used to create real objects as instances. It specifies both variables (data) and methods (functions) that all objects of the class will have. A class in Python is a user-defined data type that holds the methods for manipulating the data as well as the actual data. Classes function somewhat as an object creation template. They provide the characteristics and operations that the objects will employ. Think of it like the little metal shape you press into dough to make cookies, the cookies (objects) all have the same shape, with variations in specific details.
In contrast to other programming languages, Python’s class system introduces new classes with the least amount of additional semantics and syntax. It combines some of the C++ class mechanisms. Python classes offer every common feature of object-oriented programming, including the ability to override any method of a base class or classes, invoke methods of a base class with the same name, and support for multiple base classes through the class inheritance mechanism.
Scope and Namespaces
It’s crucial to grasp Python’s scopes and namespaces before getting into classes. A namespace, which is frequently implemented as dictionaries, is a mapping between names and objects. Local variables in a function, global variables in a module, and built-in functions are a few examples. Functions with the same name in various modules don’t conflict since names in distinct namespaces are independent.
The area of the code where a namespace is immediately accessible is referred to as a scope. Python scopes are nested:
When a variable is declared global, it refers to the global namespace of the module, whereas nonlocal refers to the namespaces of the enclosing functions. By default, variables that are not designated as global or nonlocal are handled as local.
Defining a Class in Python
Class definitions have no impact until they are run, just as function definitions (def statements) in Python. All assignments to local variables go into the newly generated namespace that is utilised as the local scope when a class definition is entered. Function definitions, specifically, bind the new function’s name here.
A class object is formed when a class definition is exited normally, that is, via the end. This essentially acts as a wrapper for the namespace that the class definition creates. To define a class in Python, see the below syntax:
Syntax:
class ClassName:
# Class body
<statement-1>
.
.
.
<statement-N>
Here, the class name is written in PascalCase after the keyword class, and methods, attributes, and statements are defined inside the class body.
What is an Object?
An object is an instance of a class with unique characteristics and functions. When we create an object, we are making use of the class’s blueprint to create a specific entity with its unique attributes and methods. Once a class has been created, objects can be created based on it. In Python, you can create an object of a class by using the class constructor. Every object may contain a unique set of data. There are two types of operations supported by class objects: instantiation and attribute references.
Attribute references:
The common syntax for all attribute references in Python is `obj.name`, which is also used for attribute references. All names that were present in the class namespace at the time the class object was formed are considered valid attribute names. The syntax is as follows:
Syntax:
object.attribute_name
Example:
class VehicleClass:
m = 569 # Class attribute
def f(self):
return 'Hello HeroVide' # Instance method
# Create an instance of the class
vehicle = VehicleClass()
# Access class attribute
print(vehicle.m) # Output: 569
# Access instance method
print(vehicle.f()) # Output: Hello HeroVide
Explanation:
In the above example, the class VehicleClass has an attribute m and a method f(). We create an instance vehicle and access both the class attribute and the instance method using the dot (.) notation.
Instantiation
Function notation is used during class instantiation. Assume, for the moment, that the class object is a parameterless function that yields a new class instance. The syntax is as follows:
Syntax:
class_name(arguments_if_any)
Example:
class Car:
def __init__(self, make, model, year):
self.make = make # Instance attribute
self.model = model # Instance attribute
self.year = year # Instance attribute
def get_description(self):
return f"{self.year} {self.make} {self.model}"
# Instantiate the Car class
my_car = Car("Tesla", "Model S", 2022)
# Access instance attributes and method
print(my_car.get_description()) # Output: 2022 Tesla Model S
Explanation:
In this example, when the class Car is instantiated with my_car = Car(“Tesla”, “Model S”, 2022), the __init__() method initialises the attributes make, model, and year. You can access them using my_car.make, my_car.model, or by calling the method get_description().
Creating Objects from a Class
We create an object by calling the class as if it were a function:
Syntax:
obj = ClassName()
Here, `obj` is an object (or instance) of the ClassName class.
Instance Variables and Methods
Instance Variables
Variables that are specific to each instance (object) of a class are known as instance variables. They are declared inside of methods. Typically, this occurs inside the class constructor, __init__. Class variables store common properties and methods shared by all instances of the class, while instance variables store data specific to each instance.
Functions defined inside a class are known as instance methods, and they are used to work with the data that an object has.
Syntax:
class ClassName:
…
def instance_method(self):
# Use self to access instance variables
return self.instance_variable
Defining Instance Variables and Methods:
Syntax:
class ClassName:
def __init__(self, parameter1):
self.instance_variable = parameter1
def instance_method(self):
# Use self to access instance variables
return self.instance_variable
Example:
class MyClass:
def __init__(self, name, year):
self.name = name # Instance variable
self.year = year # Instance variable
def myMethod(self):
return f"{self.name} says Hello!"
obj = MyClass("John!", "Hello")
print(obj.myMethod()) # Output: John says Hello!
Explanation:
Class variables are shared by all class copies and are produced independently of any class methods. Each class instance has its own set of instance variables, which are set using the self-argument in the __init__ method.
The __init__ Method (Constructor)
The __init__ method is a special method in Python (also called the constructor) that is automatically called when an object is created. It is used to initialise the object’s state. Class instantiation automatically calls __init__() for the newly formed class instance when a class defines one. There may be arguments for more flexibility with the __init__() method.
Syntax:
class ClassName:
def __init__(self, parameters):
# Initialization code
Example:
class Vehicle:
def __init__(self, name, year):
self.name = name
self.year = year
def rev(self):
return f"Car {self.name} of the year {self.year}makes sound!"
car = Vehicle("BMW", 2002)
print(car.rev()) # Output: Car BMW of the year 2002 makes sound!.
Explanation:
The __init__ method takes two parameters, name and year, which are used to initialise the instance variables of the class.
Class Variables and Methods
Class Variables
Class variables are variables that are shared by all instances of a class. They are defined inside the class but outside any method. These variables are unique to individual objects and are not shared across all instances.
Syntax:
class_variable = value
Class Methods
As instance methods act on the state of an instance of a class, the class methods are bound to the class itself, rather than to any particular instance of the class. It can modify class variables or provide functionality that applies to the entire class.
Syntax:
@classmethod
def class_method(cls, parameters):
Defining Class Variables and Methods:
Syntax:
class ClassName:
class_variable = value
@classmethod
def class_method(cls, parameters):
# Method body
Example:
class Vehicle:
company = "Mercedes" # Class variable
def __init__(self, name, model):
self.name = name # Instance variable
self.model = model # Instance variable
@classmethod
def change_company(cls, new_company):
cls.company = new_company
# All instances share the same class variable
c1 = Vehicle("E class", "Mercedes")
c2 = Vehicle("M4", "BMW")
print(c1.company) # Output: Mercedes
print(c2.company) # Output: Mercedes
# Changing the class variable using the class method
Vehicle.change_company("BMW")
print(c1.company) # Output: BMW
print(c2.company) # Output: BMW
Explanation:
In this example, the class variable company is shared by both c1 and c2 objects of the class, and when we change it using the change_company class method, it affects all instances of the class.
The self Parameter
The self-parameter is a reference to the current instance of the class and is used to access the instance variables and methods of the class. It gets passed automatically for instance methods; that’s how it allows them to modify the state of an object. The self-parameter refers to the current instance of the class and accesses the class variables. Instead of self, we can use anything. But it has to be the first parameter of any function belonging to the class.
Syntax:
class ClassName
def __init__(self, name):
self.name = name # 'self' refers to the current instance
Example:
class Car:
def __init__(self, model):
self.model = model # 'self' refers to the current instance
def show_model(self):
return f"This car is a {self.model}"
car1 = Car("Tesla Model S")
print(car1.show_model()) # Output: This car is a Tesla Model S
Explanation:
In this example, `self.model` refers to the instance variable model of the car1 object. The `self` parameter ensures that each object can maintain its unique state.
Example: Defining and Using Classes
class Vehicle:
def __init__(self, make, vtype, year):
self.make = make
self.vtype = vtype
self.year = year
def display_info(self):
return f"Vehicle: {self.year} {self.make} {self.vtype}"
# Creating instances (objects) of the Vehicle class
obj1 = Vehicle("Volvo", "Truck", 2020)
obj2 = Vehicle("BMW", "Car", 2021)
obj3 = Vehicle("Kawasaki", "Bike", 2024)
obj4 = Vehicle("Mistubishi", "Boat", 2021)
obj5 = Vehicle("Mercedes", "Car", 2023)
# Calling the method of the object
print(obj1.display_info())
print(obj2.display_info())
print(obj3.display_info())
print(obj4.display_info())
print(obj5.display_info())
Output:
Vehicle: 2020 Volvo Truck
Vehicle: 2021 BMW Car
Vehicle: 2024 Kawasaki Bike
Vehicle: 2021 Mistubishi Boat
Vehicle: 2023 Mercedes Car
Explanation:
In this example, obj1, obj2,obj3, obj4, and obj5 are instances of the Vehicle class. Each instance has its own set of attributes (make, vtype, year), and they both use the display_info method to display their details.
Inheritance in Python
Inheritance enables the member of a class to acquire properties and functions of another class, facilitating code efficiency. It represents the “is-a” relationship. A sub-class borrows all the properties and functions of a parent class (superclass).
Syntax:
class ParentClass:
def parent_method(self):
pass
class ChildClass(ParentClass):
def child_method(self):
pass
Example:
class Vehicle:
def __init__(self, name, make, year):
self.name = name
self.make = make
self.year = year
def info(self):
return f"Vehicle information is shown"
# Car inherits from Vehicle
class Car(Vehicle):
def info(self):
return f"I'm a {self.year} {self.make} {self.name}"
# Truck inherits from Vehicle
class Truck(Vehicle):
def info(self):
return f"I'm a {self.year} {self.make} {self.name}"
# Creating objects
c1 = Car("Mercedes", "M4", 2018)
t1 = Truck("Volvo", "S90", 2024)
print(c1.info())
print(t1.info())
Output:
I'm a 2018 M4 Mercedes
I'm a 2024 S90 Volvo
Explanation:
In this example, Car and Truck inherit from the Vehicle class, but each provides its implementation of the info method, demonstrating method overriding.
When the child class uses a technique that is already present in the parent class and produces its version of that method, it is called method overriding. In simple terms, the child class can recast or enhance the functions of its parent class.
Syntax:
class ParentClass:
def some_method(self):
return "Method from Parent"
class ChildClass(ParentClass):
def some_method(self):
return "Method from Child"
Example:
class Vehicle:
def info(self):
return f"I'm a Mercedes M4 2018"
# Car inherits from Vehicle
class Car(Vehicle):
# Overriding the method from Vehicle
def info(self):
return f"I'm a Mercedes M4 2018"
# Creating objects
c1 = Car()
print(c1.info())
Output:
I'm a BMW M4 2024
Explanation:
In this example, the info method is overridden in the Car class, changing the output as given in the output.
Encapsulation
Encapsulation hides the details about certain attributes or methods so that they cannot be accessed or altered without proper authorization. A simple way of achieving this is to make use of private attributes (which are usually preceded by two underscores __) or attributes protected by one underscore _.
In this example, __balance is a private attribute that cannot be accessed directly from outside the class. We have defined methods like deposit, withdraw, and get_balance to control access to this attribute.
Polymorphism in Python
Polymorphism makes it possible to treat objects of different classes as an object of the common superclass. It helps in the use of the same interface or method on different objects.
Syntax:
class ClassA:
def method(self):
pass
class ClassB(ClassA):
def method(self):
pass
Example:
class Vehicle:
# Method for Vehicle Class
def info(self):
return f"I'm a Truck type of Vehicle"
class Car:
# Method for Car Class
def info(self):
return f"I'm a Mercedes M4 2018"
# Polymorphic function
def sound(thing):
print(thing.info())
# Creating objects
c1 = Car()
v1 = Vehicle()
# call the sound method
sound(c1)
sound(v1)
Output:
I'm a Mercedes M4 2018
I'm a Truck type of Vehicle
Explanation:
Here, the sound method is defined in both the Car and Vehicle classes. The function info works with both to display the class information, demonstrating polymorphism.
Special Methods
__str__
The __str__ method is used to provide a “pretty” or user-friendly string representation of an object.
Syntax:
class ClassName:
def __str__(self):
return "String representation of the object"
Example:
class Car:
def __init__(self, name, year):
self.name = name
self.year = year
def __str__(self):
return f"This is a {self.name} {self.year}"
c1 = Car("2019", "BMW 503d")
c2 = Car("2020", "Mercedes E Class")
c3 = Car("2024", "Volvo S90")
c4 = Car("2020", "Audi A8")
print(c1)
print(c2)
print(c3)
print(c4)
Output:
This is a 2019 BMW 503d
This is a 2020 Mercedes E Class
This is a 2024 Volvo S90
This is a 2020 Audi A8
__repr__
For debugging purposes, the __repr__ method offers a more intricate or technical textual representation of an object.
Syntax:
class ClassName:
def __repr__(self):
return "Technical string representation of the object"
Example:
class Car:
def __init__(self, name, year):
self.name = name
self.year = year
def __repr__(self):
return f"Car(This is a {self.name} {self.year})"
c1 = Car("2019", "BMW 503d")
c2 = Car("2020", "Mercedes E Class")
c3 = Car("2024", "Volvo S90")
print(c1)
print(c2)
print(c3)
Output:
Car(This is a 2019 BMW 503d)
Car(This is a 2020 Mercedes E Class)
Car(This is a 2024 Volvo S90)
Static Methods vs Class Methods
Static Method
Class methods that do not have access to the instance (self) or class (cls) variables are known as static methods. When functionality relates to the class but does not affect its state, they are utilised.
Syntax:
class ClassName:
@staticmethod
def static_method_name():
# Method body
pass
Example:
class MyClass:
@staticmethod
def multiply(x, n):
return x * n
# Using static method
print(MyClass.multiply(5, 3))
Output:
15
Class Method
Class methods can change class variables and have access to the class (cls). They frequently work with production processes.
Syntax:
class ClassName:
@classmethod
def class_method_name(cls):
# Method body
pass
Example:
class Emp:
company_name = "Google"
@classmethod
def change_company(cls, new_name):
cls.company_name = new_name
# Accessing class method
print(Emp.company_name)
Emp.change_company("Microsoft")
print(Emp.company_name)
Output:
Google
Microsoft
Real-World Applications of Classes and Objects
Web Development: In Django and Flask, classes are used to manage requests and users, databases, and much more. Libraries like SQLAlchemy use classes to represent database tables. It allows you to interact with databases using Python objects.
Automation: Selenium test automation tools use classes for browser interaction and also to encapsulate test logic and data so that test management becomes easier.
Data Science: In pandas and NumPy, objects are used for data structures (like data frames and arrays). In scikit-learn, libraries use classes to represent different machine-learning models, this makes it easy to train, evaluate, and tune them.
GUI Applications: Tkinter is used to build GUI applications by creating instances from classes for Windows, widgets, etc.
Game Development: Entities including characters, enemies, and levels in games are represented using classes, therefore they are heavily used to create games using Python.
Best Practices for Classes and Objects in Python
It’s critical to adhere to best practices while working with classes and objects in Python to create software that is reliable, scalable, and maintainable. Better performance, readability, and reusability of the code are ensured by these procedures. Here are some of the best practices to follow in Python:
Class Names and its Conventions
Sticking to conventions enhances consistency, cohesiveness, and comprehensibility aspects for other people and yourself in the future. Also, in Python, class names should be the following: the first letter of each word in the name of the class should be capitalised (PascalCase).
Single Responsibility Principle (SRP)
The Single Responsibility Principle (SRP) was formulated to overcome a problem and it states that “every class should have a single, and a highly focused reason, why it has to change”. This suggests that only one reason should exist per class. It is a one-defined task per class. This principle states that classes should be made small and that they should accomplish only the specific task required and not more. This also helps in enhancing the ease of debugging and maintenance of the code.
Encapsulation
Encapsulation is the practice of hiding the internal details of an object from other objects. All this is achieved as it is one of the core concepts in OOP. This is usually done by protecting methods or using libraries and classes that offer protection from subclassing commands. This allows one to control how the state of an object is accessed and modify it, helping to avoid undue changes to a specific state. Use private (__) or protected (_) when necessary.
Avoid Plenty of Classes
While OOP encourages breaking functionality into multiple classes, too many small classes can lead to unnecessary complexity. Always aim for a balance between clarity and simplicity.
Prefer Composition Over Inheritance When Appropriate
Composition is used to construct complex objects through the assembling of other objects (or parts) rather than extending a superclass. This offers more versatility than inheritance and avoids some advantages, such as tight coupling. It’s important because composition encourages improved separation of concerns and helps in the efficient reuse of components.
Conclusion
In Python programming, classes and objects take centre stage in the OOP technique. They help the programmer organise his or her code in a manageable, reusable, and systematic way. To make the most of Python for developing scalable and maintainable applications, one must learn how to use classes and objects properly. Regardless of the type of project you embark on, whether small-scale or extensive, being able to define and use classes will enhance the quality of your code so that it is cleaner and has higher efficiency. This article has given you a complete overview of the classes and objects in Python with examples toward the end of it.
FAQs
How to create an instance of a class in Python?
To create an object of a given class, you have to simply invoke it by referring to the class, and include arguments that the init method will use. Instantiating an object is most appropriately referred to as creating an object in other instances or as the process of conducting any desire from that instance.
What is the difference between class and object variables?
Class variables are accessible to all data members of a class and are declared at the class level without being placed within methods which means all objects of that class will have the same variable. While object (or instance) variables are associated with each instance of a class and are declared inside the init function objects or other functions of that instance. Class variables have the same value for all instances, while object variables differ for every instance of the class.
What is the difference between an object and a class in Python?
A class is a blueprint for creating objects, while an object is an instance of a class. A class is a conceptual model, while an object is a tangible instance of that model. You can think of a class as a factory and an object as the product coming out of the factory.
What is __init__ in Python?
In Python, the __init__ method is a special method called a constructor which is invoked when an object of that direct subclass is being created. It initialises the object by setting initial values for its attributes. The init method also permits a programmer to enrich the specification of the object activation. In most cases, it is used to initialise the variables loaded by the object.
How to call an object in Python?
You can call an object's methods by using dot notation. You first create the object and then call its methods using the object name followed by the method name.
Syntax:
class Sum:
def add(self, p, q):
return p + q
# Creating an instance of the Sum class
sum = Sum()
# Calling a method of the object
res = sum.add(7, 8)
print(res)
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.