Classes and Objects in Python – Explained with Examples

Updated on September 30, 2024

Article Outline

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:

  1. Encapsulation: The class and the included data (attributes), and methods (functions) that operate on that data are bundled together.
  2. Inheritance: It is about new classes with attributes and methods from existing classes, enhancing code reusability.
  3. 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).
  4. Abstraction: Hiding the internal implementation details and exposing only the necessary functionalities.

 

*Image
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure

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:

 

  • Innermost: Local variables in a function.
  • Enclosing: Variables in enclosing functions.
  • Global: Module-level variables.
  • Outermost: Built-in names.

 

Example:

def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam)

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.

 

  1. 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.

 

  1. 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.

 

Syntax:

class ClassName: def __init__(self, parameter1, parameter2): self.instance_variable1 = parameter1 self.instance_variable2 = parameter2

Instance Methods

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.

 

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 _.

 

Syntax:

class ClassName: def __init__(self): self._protected_attribute = "Protected" self.__private_attribute = "Private" def get_private_attribute(self): return self.__private_attribute

Example:

class Bank: def __init__(self, ac_holder, balance): self.ac_holder = ac_holder self.__balance = balance  # Private attribute # deposit method def deposit(self, amount): self.__balance += amount # withdraw method def withdraw(self, amount): if amount <= self.__balance: self.__balance -= amount else: print("Insufficient funds") def get_balance(self): return self.__balance # Creating a Bank object account = Bank("Raman", 10900) account.deposit(5700) print("The Account balance is: ", account.get_balance()) account.withdraw(2000)

Output:

The account balance is:  16600

Explanation:

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
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.
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.
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.
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.
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)

Updated on September 30, 2024

Link
left dot patternright dot pattern

Programs tailored for your success

Popular

IIT Courses

Management

Data Science

Finance

Technology

Future Tech

Upskill with expert articles

View all
Hero Vired logo
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.
Blogs
Reviews
Events
In the News
About Us
Contact us
Learning Hub
18003093939     ·     hello@herovired.com     ·    Whatsapp
Privacy policy and Terms of use

|

Sitemap

© 2024 Hero Vired. All rights reserved