Python Classes: A Comprehensive Guide

Introduction

In Python, a class is a blueprint for creating objects (instances) that encapsulate data and functionality together. Classes define the structure and behavior of the objects, allowing you to model real-world entities in your code. Understanding classes is fundamental to writing organized, reusable, and maintainable Python programs.


Table of Contents

  1. What is a Class?

  2. Defining a Class

  3. Creating Instances (Objects)

  4. Instance Variables and Class Variables

  5. Methods in Classes

  6. Special Methods

  7. Examples and Use Cases

  8. Difference Between Classes and Functions

  9. Quick Revision Notes


What is a Class?

A class in Python is a user-defined data type that defines a set of attributes and methods. Attributes are variables that hold data, and methods are functions that define behaviors associated with an object.

  • Class: The blueprint or template for creating objects.

  • Object (Instance): An individual instance of a class containing data and methods defined by the class.


Defining a Class

You define a class using the class keyword followed by the class name and a colon. By convention, class names are written in CamelCase.

Syntax:

class ClassName:
    # Class body
    pass

Example:

class Person:
    pass

This defines an empty class named Person.


Creating Instances (Objects)

To create an instance of a class, you call the class using parentheses, similar to calling a function.

Example:

person1 = Person()
person2 = Person()

Here, person1 and person2 are two separate instances of the Person class.


Instance Variables and Class Variables

Instance Variables

  • Definition: Variables that are unique to each instance.

  • Defined in: Typically within the __init__ method.

  • Purpose: Store data unique to each object.

Example:

class Person:
    def __init__(self, name, age):
        self.name = name    # Instance variable
        self.age = age      # Instance variable

Class Variables

  • Definition: Variables that are shared among all instances of a class.

  • Defined in: Directly within the class, outside any methods.

  • Purpose: Store data that is common to all instances.

Example:

class Person:
    species = "Homo sapiens"   # Class variable

Using Instance and Class Variables:

class Person:
    species = "Homo sapiens"   # Class variable

    def __init__(self, name, age):
        self.name = name        # Instance variable
        self.age = age          # Instance variable

person1 = Person("Alice", 30)
person2 = Person("Bob", 25)

print(person1.name)       # Output: Alice
print(person2.name)       # Output: Bob
print(person1.species)    # Output: Homo sapiens
print(person2.species)    # Output: Homo sapiens

Methods in Classes

Methods are functions defined inside a class that describe the behaviors of an object.

The __init__ Method

  • Purpose: Initialize the instance variables.

  • Called: Automatically when a new instance is created.

Example:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

Instance Methods

  • Definition: Methods that operate on the instance variables of the class.

  • First Parameter: self (refers to the instance calling the method).

Example:

class Person:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, my name is {self.name}."

person = Person("Alice")
print(person.greet())    # Output: Hello, my name is Alice.

Class Methods

  • Definition: Methods that operate on the class variables.

  • Decorator: @classmethod

  • First Parameter: cls (refers to the class).

Example:

class Person:
    species = "Homo sapiens"

    @classmethod
    def get_species(cls):
        return cls.species

print(Person.get_species())    # Output: Homo sapiens

Static Methods

  • Definition: Methods that do not operate on instance or class variables.

  • Decorator: @staticmethod

  • Parameters: Do not take self or cls as the first parameter.

Example:

class Math:
    @staticmethod
    def add(a, b):
        return a + b

print(Math.add(5, 3))    # Output: 8

Special Methods

Special methods (also known as magic methods or dunder methods) are predefined methods in Python with double underscores (__) before and after their names. They allow instances of classes to interact with built-in functions and operators.

Common Special Methods

__init__(self, ...)

  • Purpose: Constructor method to initialize new instances.

  • Example:

      class Person:
          def __init__(self, name):
              self.name = name
    

__str__(self)

  • Purpose: Defines the string representation of the object for humans (used by print()).

  • Example:

      class Person:
          def __init__(self, name):
              self.name = name
    
          def __str__(self):
              return f"Person(name={self.name})"
    
      person = Person("Alice")
      print(person)    # Output: Person(name=Alice)
    

__repr__(self)

  • Purpose: Defines the official string representation of the object (used by repr()).

  • Example:

      class Person:
          def __init__(self, name):
              self.name = name
    
          def __repr__(self):
              return f"Person('{self.name}')"
    
      person = Person("Alice")
      print(repr(person))    # Output: Person('Alice')
    

Operator Overloading

You can define how operators behave with your objects by implementing special methods.

  • Addition (+): __add__(self, other)

  • Subtraction (-): __sub__(self, other)

Example:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(2, 3)
v2 = Vector(5, 7)
v3 = v1 + v2
print(v3)    # Output: Vector(7, 10)

Examples and Use Cases

Example 1: Modeling a Simple Bank Account

class BankAccount:
    bank_name = "ABC Bank"    # Class variable

    def __init__(self, account_number, balance=0):
        self.account_number = account_number    # Instance variable
        self.balance = balance                  # Instance variable

    def deposit(self, amount):
        self.balance += amount
        print(f"Deposited {amount}. New balance is {self.balance}.")

    def withdraw(self, amount):
        if amount > self.balance:
            print("Insufficient funds.")
        else:
            self.balance -= amount
            print(f"Withdrew {amount}. New balance is {self.balance}.")

    def __str__(self):
        return f"Account({self.account_number}, Balance: {self.balance})"

# Creating an account
account = BankAccount("1234567890", 1000)
print(account)                # Output: Account(1234567890, Balance: 1000)
account.deposit(500)          # Output: Deposited 500. New balance is 1500.
account.withdraw(2000)        # Output: Insufficient funds.

Example 2: Representing a Student Record

class Student:
    def __init__(self, name, grades):
        self.name = name            # Instance variable
        self.grades = grades        # Instance variable (list of grades)

    def average_grade(self):
        return sum(self.grades) / len(self.grades)

student = Student("Bob", [85, 90, 78])
print(f"{student.name}'s average grade is {student.average_grade():.2f}")
# Output: Bob's average grade is 84.33

Example 3: Using Class and Static Methods

class TemperatureConverter:
    @staticmethod
    def celsius_to_fahrenheit(celsius):
        return (celsius * 9/5) + 32

    @staticmethod
    def fahrenheit_to_celsius(fahrenheit):
        return (fahrenheit - 32) * 5/9

print(TemperatureConverter.celsius_to_fahrenheit(0))    # Output: 32.0
print(TemperatureConverter.fahrenheit_to_celsius(98.6)) # Output: 37.0

Difference Between Classes and Functions

Classes

  • Definition: Blueprints for creating objects that can hold data (attributes) and have associated behaviors (methods).

  • Stateful: Can maintain state across multiple method calls within an instance.

  • Instantiation: Can create multiple instances, each with its own state.

Functions

  • Definition: Blocks of reusable code that perform a specific task.

  • Stateless: Do not maintain state between calls unless using external variables.

  • Execution: Invoked directly and execute code immediately.

Key Differences

  1. State Maintenance:

    • Classes: Maintain state via instance variables.

    • Functions: Do not inherently maintain state.

  2. Reusability and Modularity:

    • Classes: Encapsulate data and behaviors; suitable for modeling complex systems.

    • Functions: Ideal for simple, standalone operations.

  3. Usage:

    • Classes: Used when you need to model entities with attributes and behaviors.

    • Functions: Used for operations that don't require maintaining state.

Example Comparing Class and Function:

# Using a Function
def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))   # Output: Hello, Alice!

# Using a Class
class Greeter:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, {self.name}!"

greeter = Greeter("Bob")
print(greeter.greet())  # Output: Hello, Bob!

Quick Revision Notes

Class Definition

  • Syntax:

      class ClassName:
          # Class body
          pass
    

Creating Instances

  • Instantiation:

      instance = ClassName()
    

Instance Variables

  • Defined within methods, usually __init__.

  • Unique to each instance.

Class Variables

  • Defined directly under the class.

  • Shared among all instances.

Methods

  • Instance Methods: Operate on instance variables; self as first parameter.

  • Class Methods: Operate on class variables; cls as first parameter; use @classmethod.

  • Static Methods: Do not operate on instance or class variables; no self or cls; use @staticmethod.

Special Methods

  • __init__: Constructor for initializing instances.

  • __str__: Defines informal string representation (used by print()).

  • __repr__: Defines official string representation.

  • Operator Overloading: Define how operators work with objects (e.g., __add__, __sub__).

Accessing Attributes and Methods

  • Attributes: Accessed using dot notation (object.attribute).

  • Methods: Called using dot notation (object.method()).

Key Points

  • Classes encapsulate data and functionality.

  • Use self to refer to instance variables and methods.

  • Classes can have multiple instances, each with its own state.

  • Functions within a class are called methods.


Conclusion

Classes in Python are powerful tools for creating structured and organized code. They allow you to model complex data structures and behaviors, promoting code reusability and clarity. Understanding the features of classes, such as instance variables, class variables, methods, and special methods, is essential for effective programming in Python.


0
Subscribe to my newsletter

Read articles from Sai Prasanna Maharana directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sai Prasanna Maharana
Sai Prasanna Maharana