Python Classes & OOP
Object-oriented programming related data aur behavior ko ek structured object me organize karne ka way hai. Is chapter me classes, objects, constructors, attributes, methods, encapsulation aur composition ko practical examples ke saath samjhenge.
What is object-oriented programming?
OOP me program ko objects ke around model kiya jata hai. Object ke paas state (data) aur behavior (methods) ho sakte hain. Python multi-paradigm language hai, so har problem ko class me convert karna zaroori nahi.
Student ko sirf dictionary se represent kar sakte ho, lekin jab student ke data ke saath methods bhi chahiye — jaise average calculate karna ya result show karna — class useful ho sakti hai.
Class and object
A class is a blueprint/type definition. An object is an instance created from that class.
class Student:
pass
student_one = Student()
student_two = Student()
print(type(student_one))
print(student_one is student_two)Both objects same class ke instances hain, but separate objects hain.
__init__ and object initialization
__init__ instance creation ke immediately after initialization ke liye commonly used special method hai.
class Student:
def __init__(self, name, course):
self.name = name
self.course = course
student = Student("Aman", "Python")
print(student.name)
print(student.course)self.name and self.course instance attributes hain. Har instance apni values rakh sakta hai.
What is self?
self current instance ko refer karta hai. Ye reserved keyword nahi hai, but Python convention strongly self naam use karti hai. Instance method call me Python instance ko first argument ke roop me pass karta hai.
class Greeter:
def greet(self):
print("Hello from", self)
g = Greeter()
g.greet()Instance methods
Instance method object ke state ko read ya modify kar sakta hai.
class BankAccount:
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
def show_balance(self):
return self.balance
account = BankAccount("Riya", 1000)
account.deposit(500)
print(account.show_balance())Method ke through state update karne se validation ek central place par rakhi ja sakti hai.
Instance attributes vs class attributes
class Student:
platform = "BrounStack"
def __init__(self, name):
self.name = name
first = Student("Aman")
second = Student("Riya")
print(first.name, first.platform)
print(second.name, second.platform)name instance-specific hai. platform class attribute hai and class namespace se shared/default lookup hota hai.
__init__ me create karo.Mutable class attribute gotcha
class WrongCart:
items = []
def add(self, item):
self.items.append(item)
one = WrongCart()
two = WrongCart()
one.add("Book")
print(two.items) # same shared listCorrect approach: self.items = [] inside __init__.
Validate state inside methods
class Student:
def __init__(self, name, score):
self.name = name
self.set_score(score)
def set_score(self, score):
if not 0 <= score <= 100:
raise ValueError("score must be 0 to 100")
self.score = score
student = Student("Kabir", 88)
print(student.score)Object ko valid state me rakhna class design ka important goal hai.
Encapsulation in Python
Python strict private fields ko Java/C++ style enforce nahi karta. Naming conventions intent communicate karti hain:
name— public attribute._name— internal-use convention; external code ko caution signal.__name— name mangling trigger karta hai; true security/privacy boundary nahi.
class Account:
def __init__(self, balance):
self._balance = balance
def get_balance(self):
return self._balancePython culture often unnecessary getters/setters se bachti hai; simple public attributes fine ho sakte hain until validation/computation needed ho.
Properties for controlled attribute access
class Student:
def __init__(self, score):
self.score = score
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not 0 <= value <= 100:
raise ValueError("score must be 0 to 100")
self._score = value
student = Student(90)
student.score = 95
print(student.score)Property method logic ko normal attribute syntax ke peeche expose kar sakti hai. Use only when it improves API clarity.
Class methods
@classmethod first argument me class receive karta hai, conventionally cls. Alternative constructors ek common use case hain.
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
@classmethod
def from_text(cls, text):
name, score = text.split(",")
return cls(name.strip(), float(score))
student = Student.from_text("Aman,88")
print(student.name, student.score)Static methods
@staticmethod automatic self ya cls receive nahi karta. It can be useful for helper logic conceptually related to the class, but many helpers ordinary module functions bhi ho sakte hain.
class Grade:
@staticmethod
def is_valid(score):
return 0 <= score <= 100
print(Grade.is_valid(85))Composition — objects inside objects
Composition means one object another object ko contain/use karta hai. “Has-a” relationship ke liye useful hai.
class Address:
def __init__(self, city):
self.city = city
class Student:
def __init__(self, name, address):
self.name = name
self.address = address
address = Address("Lucknow")
student = Student("Riya", address)
print(student.name, student.address.city)Composition often small focused classes ko combine karke flexible design deta hai.
OOP concepts — where they fit
- Encapsulation: related state and behavior ko class me organize karna, valid state protect karna.
- Abstraction: user ko simple interface dena while implementation details hide karna.
- Inheritance: one class another class se behavior reuse/extend kare — Chapter 17 me detail.
- Polymorphism: different objects same interface ko support kar sakte hain — Chapter 17 me practical examples.
String representation preview
Default object print usually memory-style representation dikhata hai. Special methods such as __str__ and __repr__ readable/debug representations define kar sakte hain; detailed data-model discussion Chapter 17 me hogi.
class Student:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Student: {self.name}"
print(Student("Aman"))When should you use a class?
- Data and related behavior naturally belong together.
- Multiple similar objects create karne hain.
- Object ko valid state maintain karna hai.
- Domain concept ko clear interface dena hai.
- Composition/reusable behavior se design easier hota hai.
Simple transformation, one-off script, ya stateless calculation ke liye function/dictionary sometimes simpler and better choice hai.
Practical example — StudentResult
class StudentResult:
def __init__(self, name, marks):
self.name = name
self.marks = list(marks)
def average(self):
if not self.marks:
return 0
return sum(self.marks) / len(self.marks)
def grade(self):
score = self.average()
if score >= 90:
return "A"
if score >= 75:
return "B"
if score >= 60:
return "C"
return "D"
result = StudentResult("Aman", [82, 91, 76])
print(f"{result.name}: {result.average():.2f} ({result.grade()})")Constructor data initialize karta hai; methods calculations ko object ke behavior ke roop me organize karte hain.
Common beginner mistakes
- Method definition me
selfbhool jana. self.name = nameki jagah sirf localnamevariable banana.- Har small function ko unnecessary class me convert karna.
- Mutable class attribute ko per-instance data samajhna.
- Class aur instance attribute difference ignore karna.
- Object state ko invalid values me freely chhod dena.
__init__se value return karne ki koshish karna.__privateko security mechanism samajhna.- Getter/setter boilerplate copy karna jab simple attribute enough ho.
- Inheritance ko composition se pehle default choice banana.
Beginner best practices
- Class names ke liye
PascalCaseuse karo. - Methods and attributes ke liye clear
snake_casenames use karo. - Class ko one clear responsibility ke around design karo.
- Constructor ko predictable rakho; heavy side effects avoid karo.
- Invalid state ko early validate karo.
- Simple design prefer karo; abstraction only when useful ho.
- Composition ko seriously consider karo before deep inheritance.
- Public interface clear rakho and internal details unnecessarily expose mat karo.
Chapter checklist
- Class aur object ka difference clear hai?
__init__aurselfka role samajh aaya?- Instance attributes and methods bana sakte ho?
- Class vs instance attributes ka difference clear hai?
- Mutable class attribute risk samajh aaya?
- Property se validation implement kar sakte ho?
@classmethodand@staticmethodka basic use pata hai?- Composition ka “has-a” relationship samajh aaya?
Practice Task — Course Enrollment Manager
Classes use karke small enrollment system banao.
Courseclass banao with title and maximum seats.Studentclass banao with name and email.Enrollmentclass banao jo student and course objects contain kare.Courseme enrolled-students collection per instance rakho.enroll()method banao.- Duplicate enrollment prevent karo.
- Maximum seats validate karo.
- Invalid seat count par
ValueErrorraise karo. available_seats()method banao.- One class attribute add karo, e.g. platform name.
- One property use karke validated field expose karo.
- One
@classmethodalternative constructor try karo. - Readable
__str__preview add karo. - At least two students and one course ke saath test karo.