Python Classes & Objects

🐍 Python Classes & Objects

OOP • Python • Hands-on

In Python, everything is an object. Numbers, strings, lists, even functions. To create your own structured data types with behavior, you use classes. A class is a blueprint; an object (or instance) is the thing built from that blueprint. This guide covers what they are, why they matter, and how to use them with step-by-step code.

📌 What are Classes & Objects?

Class → A blueprint (template) that defines attributes (data) and methods (functions).

Object (Instance) → A specific realization of a class; it carries its own data values.

# Real-world analogy: Class = Recipe, Object = Cake

class Dog:
    species = "Canis familiaris"   # class attribute (shared)
    
# Create objects (instances)
a = Dog()
b = Dog()
print(a.species, b.species)  # Canis familiaris Canis familiaris

🎯 Uses & Characteristics

Why use classes?
  • Encapsulation: keep data + behavior together
  • Reusability: one class → many objects
  • Abstraction: hide internal details
  • Maintainability: structure large codebases
Key characteristics
  • Objects from the same class can hold different values
  • Support for inheritance & polymorphism (advanced OOP)
  • Attributes are dynamic—can be added/modified/removed at runtime

💻 Syntax, Create a Class & Object

class ClassName:
    "Optional docstring explaining the class"
    class_attr = 123  # shared by all instances

    def method_name(self, param):
        # self refers to the instance
        return param

# Example
class Student:
    school = "Greenwood High"   # class attribute
    def __init__(self, name, grade):  # constructor
        self.name = name         # instance attribute
        self.grade = grade

s1 = Student("Aisha", "A")
s2 = Student("Ravi", "B")
print(s1.name, s2.name)  # Aisha Ravi
print(s1.school, s2.school)  # Greenwood High Greenwood High

⚡ The __init__() Constructor

Runs automatically when you create an object. Use it to initialize instance attributes.
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance  # default value

acc = BankAccount("Neha")
print(acc.owner, acc.balance)  # Neha 0

🖨️ The __str__() Method

Return a friendly string when the object is printed (e.g., via print(obj)).
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
    def __str__(self):
        return f"Account(owner={self.owner}, balance={self.balance})"

acc = BankAccount("Neha", 500)
print(acc)  # Account(owner=Neha, balance=500)

🛠️ Methods & the self Parameter

self is the current object. It must be the first parameter of instance methods.
class Counter:
    def __init__(self):
        self.value = 0
    def increment(self, step=1):
        self.value += step
        return self.value
    def reset(self):
        self.value = 0

c = Counter()
c.increment()       # 1
c.increment(4)      # 5
print(c.value)      # 5
c.reset()
print(c.value)      # 0

✏️ Modify / 🗑️ Delete Properties & Objects

Modify a property
c = Counter()
c.increment(10)
c.value = 99           # modify
print(c.value)         # 99
Delete a property
del c.value
# Accessing c.value now raises: AttributeError
Delete an object
del c
# NameError if you try to use c after this
Note: Deleting the last reference lets Python’s garbage collector reclaim memory automatically.

⏸️ The pass Statement

Use pass as a placeholder when you want a syntactically complete class or method but no logic yet.
class Placeholder:
    pass

class Todo:
    def create(self):
        pass    # implement later

⚖️ Classes vs Objects

Class Object
Blueprint / template Concrete instance created from the class
Defines attributes & methods Holds actual values, calls methods
One definition in code Many objects possible

🧪 Mini Project: BankAccount

class BankAccount:
    bank_name = "PyBank"  # class attribute (shared)
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Amount must be positive")
        self.balance += amount
        return self.balance
    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient funds")
        self.balance -= amount
        return self.balance
    def __str__(self):
        return f"{self.owner} @ {self.bank_name} → ₹{self.balance}"

acc = BankAccount("Rohit", 1000)
acc.deposit(500)
print(acc)           # Rohit @ PyBank → ₹1500
acc.withdraw(300)
print(acc)           # Rohit @ PyBank → ₹1200
Why it’s useful: shows __init__, methods, validation, class vs instance attributes, and __str__.

🚩 Common Mistakes & Fixes

  • Forgetting self in method definitions → TypeError: ... 1 positional argument ...
  • Shadowing class attributes by accident (e.g., self.bank_name = ... when you meant the shared one)
  • Not initializing needed attributes in __init__, then getting AttributeError later

🧩 Exercises (Practice & Apply)

  1. Rectangle: attributes width, height; methods area(), perimeter().
  2. Car: attributes make, model, year, speed=0; methods accelerate(), brake(), __str__().
  3. Student: store a list of marks; method average() with safe handling for empty lists.
  4. TodoList: methods add(), remove(), list_tasks(); show how deleting attributes affects behavior.
  5. Temperature: create a method to convert between °C and °F; use __str__() to format output.
  6. Counter (Bonus): add an optional max_value and stop increment when reached.

❓ FAQ

Q1. Why do methods need self?
It tells Python which object’s data to use. Without it, the method has no instance to act on.
Q2. Can a class have multiple __init__?
No. Use default parameters or @classmethod factories to support multiple creation styles.
Q3. Difference: __str__ vs __repr__?
__str__ → human-friendly; __repr__ → unambiguous/debug-friendly (often could recreate the object).
Q4. What happens after del obj?
The name reference is removed. If no references remain, Python can free the memory.
Q5. Class attribute vs instance attribute?
Class attribute is shared by all instances; instance attribute belongs to one object.

🧠 Glossary (One-liners)

Class: Blueprint for objects.
Object: Instance with real data.
Attribute: Data stored on an object.
Method: Function defined in a class.
__init__: Constructor; sets initial state.
__str__: Human-friendly print string.
self: Reference to the current object.

✅ Conclusion

Classes & objects are the core of Python’s OOP. Start with constructors, methods, and self, then practice by building small models (BankAccount, Student, Car). As you grow, explore inheritance, composition, and __repr__. The best way to learn OOP is to code real examples.

Post a Comment

0 Comments