प्रस्तावना (Introduction)
Python मध्ये सुरुवातीला Variables, Data Types, Conditions, Loops आणि Functions शिकल्यानंतर छोटे programs लिहिणं फारसं कठीण वाटत नाही. पण application थोडं मोठं झालं की एक वेगळी अडचण समोर येते.
समजा तुम्ही Student Management System बनवत आहात.
सुरुवातीला काही students साठी variables तयार करून काम भागू शकतं:
student1_name = "Amit" student1_marks = 78 student2_name = "Sneha" student2_marks = 85
पण students 10, 100 किंवा 10,000 झाले तर?
प्रत्येक student साठी वेगवेगळे variables आणि functions लिहिणं, त्यांचा data manage करणं आणि code maintain करणं अवघड होईल.
इथे Object-Oriented Programming म्हणजेच OOP उपयोगी पडतं.
OOP मध्ये आपण related data आणि त्या data वर काम करणारा logic एका structured unit मध्ये ठेवू शकतो. Python मध्ये class हा अशा प्रकारे data आणि functionality एकत्र organize करण्याचा मुख्य मार्ग आहे.
OOP म्हणजे नक्की काय?
OOP म्हणजे Object-Oriented Programming.
सोप्या भाषेत सांगायचं तर, application मधील related data आणि behaviour यांना objects आणि classes च्या माध्यमातून व्यवस्थित organize करण्याची programming पद्धत म्हणजे OOP. उदाहरण म्हणून Student घेऊ.
एका student बद्दल आपल्याकडे:
Data:
- नाव
- roll number
- marks
- course
Behaviour:
- marks update करणे
- result calculate करणे
- student ची माहिती दाखवणे
हे सगळं वेगवेगळ्या variables आणि functions मध्ये विखुरण्याऐवजी Student नावाच्या class मध्ये organize करता येतं.
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def result(self):
if self.marks >= 35:
return "Pass"
return "Fail"आता:
student1 = Student("Amit", 78)
print(student1.name)
print(student1.result())Output:
Amit Pass
इथे Student हा class आहे आणि student1 हा त्या class चा object आहे.
Class म्हणजे काय?
Class म्हणजे एखाद्या प्रकारच्या objects साठी structure आणि behaviour define करणारा template.
उदा:
class Student:
passइथे आपण Student नावाचा class तयार केला.
Class स्वतः student ची actual information नाही. तो student object मध्ये कोणता data आणि कोणत्या methods असतील याची रचना define करतो.
थोडक्यात:
Class → Structure / Design Object → त्या class वरून तयार झालेली actual instance
एक practical example
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def show_result(self):
if self.marks >= 35:
print(f"{self.name} Pass आहे")
else:
print(f"{self.name} Fail आहे")आता या class वरून अनेक objects तयार करू शकतो:
s1 = Student("Amit", 78)
s2 = Student("Sneha", 91)
s3 = Student("Rahul", 32)तीनही objects चा structure समान आहे, पण त्यांच्यातील data वेगळा आहे.
Object म्हणजे काय?
Object म्हणजे class ची actual instance.
s1 = Student("Amit", 78)इथे:
Student→ Classs1→ Object"Amit"→ Object चा data78→ Object चा data
एकाच class पासून अनेक objects तयार करता येतात.
s1 = Student("Amit", 78)
s2 = Student("Sneha", 91)दोघांकडे name आणि marks आहेत, पण values वेगळ्या आहेत.
हेच OOP चं एक महत्त्वाचं advantage आहे.
Object मध्ये State, Behaviour आणि Identity म्हणजे काय?
OOP समजताना हे तीन शब्द उपयोगी पडतात.
1. State
Object मधील data म्हणजे त्याची state.
s1.name s1.marks
2. Behaviour
Object काय काम करू शकतो ते त्याचं behaviour.
s1.show_result()
3. Identity
प्रत्येक object स्वतंत्र instance असतो.
s1 = Student("Amit", 78)
s2 = Student("Amit", 78)दोघांचा data सारखा असला तरी s1 आणि s2 हे दोन वेगळे objects आहेत.
self म्हणजे काय?
Python OOP शिकताना beginners ना सर्वात जास्त confusion देणाऱ्या गोष्टींपैकी एक म्हणजे self.
उदा:
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marksइथे self म्हणजे ज्या object वर method चालत आहे तो current object.
समजा:
s1 = Student("Amit", 78)
s2 = Student("Sneha", 91)जेव्हा:
s1.show_result()
चालतो, तेव्हा method s1 object च्या data वर काम करते.
आणि:
s2.show_result()
चालवल्यावर तीच method s2 च्या data वर काम करते. म्हणून self.name म्हणजे current object चं name.
एक common mistake
हे चुकीचं:
class Student:
def __init__(name, marks):
self.name = nameकारण instance method मध्ये current instance साठी पहिला parameter असतो.
योग्य:
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marksएक महत्त्वाची गोष्ट: self हा Python मधला reserved keyword नाही; तो एक conventional parameter name आहे. पण instance methods मध्ये त्याच अर्थाने self वापरणं standard आणि readable पद्धत आहे.
__init__() म्हणजे काय?
__init__() ही special method आहे जी object तयार झाल्यानंतर त्याची initial state सेट करण्यासाठी वापरली जाते.
उदा.:
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salaryआता:
emp = Employee("Ravi", 50000)object तयार करताना name आणि salary initialize होतात. एक technical clarification लक्षात ठेवा:
__init__() ला अनेक tutorials मध्ये constructor म्हटलं जातं, पण Python मध्ये object creation आणि initialization वेगवेगळ्या टप्प्यांमध्ये होतात. __new__() object तयार करण्यासाठी आणि __init__() तयार झालेल्या object ला initialize करण्यासाठी वापरली जाते.
बहुतेक सामान्य classes मध्ये तुम्हाला __new__() manually लिहिण्याची गरज पडत नाही.
Instance Variable आणि Class Variable
हा topic real projects मध्ये खूप महत्त्वाचा आहे.
Instance Variable
प्रत्येक object साठी वेगळा data.
class Student:
def __init__(self, name):
self.name = nameइथे:
s1 = Student("Amit")
s2 = Student("Sneha")name प्रत्येक object साठी वेगळं आहे.
Class Variable
Class level वर ठेवलेला attribute.
class Student:
school_name = "ABC School"
def __init__(self, name):
self.name = nameआता:
s1 = Student("Amit")
s2 = Student("Sneha")
print(s1.school_name)
print(s2.school_name)दोन्ही objects class attribute शोधू शकतात.
Python मध्ये class आणि instance attributes चं lookup behaviour समजून घेणं महत्त्वाचं आहे, कारण instance attribute आणि class attribute एकाच नावाने असतील तर instance-level value ला precedence मिळते.
Python OOP चे Four Common Concepts
OOP शिकताना खालील चार concepts सर्वाधिक चर्चेत येतात:
- Inheritance
- Polymorphism
- Encapsulation
- Abstraction
पण एक महत्त्वाची गोष्ट:
हे चार शब्द फक्त definitions म्हणून पाठ करण्यापेक्षा problem solve करताना त्यांचा उपयोग काय आहे हे समजणं जास्त महत्त्वाचं आहे.
Inheritance म्हणजे काय?
Inheritance मध्ये एक class दुसऱ्या class मधील behaviour किंवा attributes reuse करू शकतो.
उदा.:
class Animal:
def eat(self):
print("Animal खात आहे")
class Dog(Animal):
def bark(self):
print("Dog भुंकत आहे")आता:
dog = Dog() dog.eat() dog.bark()
Dog class मध्ये eat() लिहिलेली नाही, तरी ती Animal कडून मिळते.
Inheritance चा फायदा
जर अनेक classes मध्ये common behaviour असेल तर ते पुन्हा पुन्हा लिहिण्याची गरज कमी होते.
उदा.:
Animal ├── Dog ├── Cat └── Cow
Common behaviour Animal मध्ये ठेवता येतो.
पण प्रत्येक वेळी inheritance वापरायचं का?
नाही. फक्त code reuse करण्यासाठी inheritance वापरणं योग्य design असेलच असं नाही.
जर relationship स्पष्टपणे “is-a” असेल तर inheritance विचारात घेता येतो.
उदा.:
Dog is an Animal Car is a Vehicle
पण:
Car has an Engine
इथे inheritance पेक्षा Composition जास्त natural आहे.
Polymorphism म्हणजे काय?
Polymorphism म्हणजे एकाच interface किंवा method call ला वेगवेगळ्या objects कडून वेगवेगळं behaviour मिळणं.
उदा:
class Dog:
def sound(self):
print("भुंकणे")
class Cat:
def sound(self):
print("म्याव")
animals = [Dog(), Cat()]
for animal in animals:
animal.sound()Output:
भुंकणे म्याव
Loop ला हे माहीत असण्याची गरज नाही की object Dog आहे की Cat.
त्याला फक्त एवढं माहीत आहे:
animal.sound()
यामुळे code अधिक flexible होतो. Python मध्ये यासोबत duck typing ही कल्पना देखील महत्त्वाची आहे. म्हणजे object कोणत्या class चा आहे यापेक्षा तो आवश्यक behaviour देतो का हे अनेक परिस्थितींमध्ये अधिक महत्त्वाचं ठरतं.
Encapsulation म्हणजे काय?
Encapsulation म्हणजे data आणि त्या data वर काम करणारा logic एका class मध्ये organize करून बाहेरून होणाऱ्या चुकीच्या manipulation वर नियंत्रण ठेवण्याची design पद्धत.
उदा. Bank Account:
class BankAccount:
def __init__(self, balance):
self.__balance = balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self):
return self.__balanceआता:
account = BankAccount(1000) account.deposit(500) print(account.get_balance())
Output:
1500
इथे balance वर थेट काम करण्याऐवजी deposit() सारख्या method मधून rule लागू करता येतो.
उदा.:
if amount > 0:
यामुळे invalid amount थांबवता येतो.
Python मध्ये __balance खरंच private आहे का?
इथे एक common misconception आहे. Python मध्ये Java किंवा C++ सारखं strict private access control नाही.
Double underscore:
self.__balance
यामुळे name mangling होतं.
म्हणून __balance हा attribute normal बाह्य access पासून लपवण्यास मदत करतो, पण तो security boundary नाही.
म्हणून:
Encapsulation म्हणजे “data पूर्णपणे inaccessible करणे” नाही; controlled access आणि implementation details व्यवस्थित organize करणे हा त्याचा practical उपयोग आहे.
Python च्या documentation मध्येही private variables बाबत Python ची approach convention आणि name mangling वर आधारित असल्याचं स्पष्ट केलं आहे.
Abstraction म्हणजे काय?
Abstraction म्हणजे user ला आवश्यक interface देणे आणि implementation ची अनावश्यक complexity मागे ठेवणे.
उदा. ATM वापरताना तुम्ही:
- पैसे काढता
- balance check करता
- PIN वापरता
पण transaction database मध्ये कशी process होते, authentication कसं होतं, backend मध्ये कोणते queries चालतात हे प्रत्येक user ला माहीत असण्याची गरज नसते.
Python मध्ये abstract base classes तयार करण्यासाठी abc module वापरता येतो.
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def pay(self, amount):
pass
class UPI(Payment):
def pay(self, amount):
print(f"UPI द्वारे ₹{amount} payment झाले")
class Card(Payment):
def pay(self, amount):
print(f"Card द्वारे ₹{amount} payment झाले")आता:
payments = [UPI(), Card()]
for payment in payments:
payment.pay(1000)इथे Payment एक common interface देतो आणि प्रत्येक implementation आपापल्या पद्धतीने pay() करते.
Encapsulation आणि Abstraction मध्ये फरक
हे दोन concepts beginners अनेकदा एकसारखे समजतात.
सोपं लक्षात ठेवा:
Encapsulation
Data आणि behaviour कसं organize आणि control करायचं?
उदा.:
self.__balance
Abstraction
User ला काय interface द्यायचं आणि implementation मधील complexity किती लपवायची?
उदा.:
payment.pay(1000)
User ला payment process ची पूर्ण internal implementation माहित असण्याची गरज नाही.
थोडक्यात:
Encapsulation → How to control/organize? Abstraction → What should the user need to know?
super() म्हणजे काय?
Inheritance वापरताना child class मधून parent class ची functionality वापरण्यासाठी super() उपयोगी पडतो.
class Person:
def __init__(self, name):
self.name = name
class Student(Person):
def __init__(self, name, marks):
super().__init__(name)
self.marks = marksइथे:
super().__init__(name)
मुळे parent class चा initialization logic पुन्हा लिहावा लागत नाही. याचा फायदा म्हणजे common initialization logic एका ठिकाणी राहतो.
Method Overriding म्हणजे काय?
Child class parent class मधील method स्वतःच्या behaviour नुसार redefine करते, त्याला method overriding म्हणतात.
class Animal:
def sound(self):
print("Animal sound")
class Dog(Animal):
def sound(self):
print("Bark")आता:
dog = Dog() dog.sound()
Output:
Bark
Dog ने parent च्या sound() ला स्वतःच्या implementation ने override केलं.
classmethod आणि staticmethod
Instance Method
Object च्या data वर काम:
class Student:
def __init__(self, name):
self.name = name
def show_name(self):
return self.nameइथे self वापरला आहे.
Class Method
Class level data किंवा alternate object creation सारख्या use cases साठी cls वापरला जातो.
class Student:
school = "ABC School"
@classmethod
def change_school(cls, name):
cls.school = nameStatic Method
Object किंवा class च्या state ची गरज नसलेला related utility logic class मध्ये ठेवायचा असेल तर staticmethod वापरता येतो.
class Student:
@staticmethod
def is_pass(marks):
return marks >= 35यात self किंवा cls ची गरज नाही.
लक्षात ठेवण्याचा सोपा rule
self → Object-level data cls → Class-level data none → Independent utility logic
OOP मध्ये Inheritance पेक्षा Composition कधी वापरायची?
हा topic beginner tutorials मध्ये अनेकदा दुर्लक्षित केला जातो, पण practical software design मध्ये तो महत्त्वाचा आहे.
समजा:
Car has an Engine
Engine हा Car चा प्रकार नाही.
म्हणून:
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self.engine = Engine()
def start(self):
self.engine.start()
print("Car started")इथे Car मध्ये Engine चा object आहे. याला Composition म्हणतात.
फरक
Inheritance: Dog is an Animal Composition: Car has an Engine
Inheritance मध्ये “is-a” relationship असतो. Composition मध्ये “has-a” relationship असतो.
Real project मध्ये कोणता approach वापरायचा हे relationship, responsibilities आणि future changes यावर अवलंबून असतं. फक्त code reuse करण्यासाठी inheritance निवडण्यापेक्षा design relationship समजून घेणं महत्त्वाचं आहे.
आता एक Practical OOP Project बनवूया
आता वेगवेगळे concepts वेगवेगळे पाहण्यापेक्षा त्यांना एका छोट्या project मध्ये जोडूया. समजा आपण Employee Management System चा basic भाग बनवत आहोत.
आपल्याकडे:
Employee ↓ Developer ↓ Manager
पण Developer आणि Manager दोघांकडे common employee information आहे.
म्हणून base class:
class Employee:
company = "Learn Grow"
def __init__(self, name, salary):
self.name = name
self.salary = salary
def show_details(self):
print(f"Name: {self.name}")
print(f"Salary: ₹{self.salary}")
def work(self):
print("Employee is working")आता Developer:
class Developer(Employee):
def __init__(self, name, salary, language):
super().__init__(name, salary)
self.language = language
def work(self):
print(f"{self.name} {self.language} मध्ये coding करत आहे")Manager:
class Manager(Employee):
def work(self):
print(f"{self.name} team manage करत आहे")आता objects:
employees = [
Developer("Amit", 60000, "Python"),
Manager("Sneha", 80000)
]आणि:
for employee in employees:
employee.show_details()
employee.work()इथे एकाच list मध्ये वेगवेगळ्या प्रकारचे objects आहेत.
पण:
employee.work()
केल्यावर object नुसार वेगळं behaviour मिळतं. यातून आपल्याला एकाच छोट्या project मध्ये:
- Class
- Object
- Instance variable
- Class variable
- Inheritance
super()- Method overriding
- Polymorphism
हे concepts दिसतात. याच प्रकारे मोठ्या application मध्ये classes एकमेकांशी काम करतात.
OOP कधी वापरायचं?
हा प्रश्न “OOP म्हणजे काय?” पेक्षा काही वेळा जास्त महत्त्वाचा आहे. प्रत्येक Python program साठी class बनवण्याची गरज नसते.
छोटा script
उदा.:
a = 10 b = 20 print(a + b)
इथे OOP वापरण्याची गरज नाही.
Simple utility
एखादं छोटं calculation किंवा file conversion script असेल तर functions पुरेसे असू शकतात.
मोठं application
उदा.:
- E-commerce application
- Banking system
- Student Management System
- Inventory Management
- Game
- API backend
- मोठं automation framework
अशा systems मध्ये अनेक entities आणि behaviours असल्यामुळे OOP उपयोगी ठरू शकतं.
साधा विचार
स्वतःला प्रश्न विचारा:
“या problem मध्ये अनेक entities आहेत का? प्रत्येक entity चा स्वतःचा data आणि behaviour आहे का?”
जर उत्तर हो असेल तर class-based design विचारात घेता येतो.
Python Projects मध्ये OOP कुठे दिसतं?
Python च्या ecosystem मध्ये OOP फक्त textbook topic नाही.
Web frameworks, libraries आणि applications मध्ये classes मोठ्या प्रमाणावर वापरल्या जातात.
उदा.:
Web Development
Django सारख्या frameworks मध्ये models, forms, views इत्यादी अनेक ठिकाणी class-based design आढळतो.
Game Development
Player Enemy Weapon Game Level
अशा entities classes म्हणून model करता येतात.
Automation
EmailSender FileProcessor ReportGenerator DatabaseManager
प्रत्येकाची responsibility वेगळी ठेवता येते.
API / Backend
User Product Order Payment Notification
अशा entities चं logic व्यवस्थित organize करता येतं.
म्हणून OOP चा उद्देश फक्त “class कशी लिहायची?” एवढाच नाही.
मोठ्या codebase मध्ये responsibility व्यवस्थित organize करणं हा त्याचा practical फायदा आहे.
Beginners कडून होणाऱ्या Common OOP Mistakes
1. प्रत्येक गोष्टीसाठी class तयार करणे
OOP शिकल्यानंतर काही beginners प्रत्येक छोट्या function साठी class तयार करतात.
हे आवश्यक नाही. Simple problem असेल तर simple solution ठेवा.
2. self विसरणे
def show_name():
याऐवजी instance method मध्ये:
def show_name(self):
3. Class variable आणि instance variable गोंधळणे
class Student:
school = "ABC"
def __init__(self, name):
self.name = nameschool आणि name ची भूमिका वेगळी आहे.
4. फक्त code reuse साठी inheritance वापरणे
Inheritance वापरण्यापूर्वी relationship विचारात घ्या.
is-a → Inheritance विचारात घ्या has-a → Composition विचारात घ्या
हा कठोर नियम नाही, पण design करताना उपयोगी starting point आहे.
5. __private म्हणजे security असा गैरसमज
Python मधील name mangling हा security mechanism नाही. Sensitive data साठी actual security mechanisms वेगळे असतात.
OOP शिकताना एक Practical Learning Path

वारंवार विचारले जाणारे प्रश्न (FAQs)
Q1. Class आणि Object मध्ये नेमका फरक काय?
Ans: Class हा एक blueprint/साचा आहे, तर Object हा त्या साच्यावरून तयार झालेली प्रत्यक्ष वस्तू आहे. एका class पासून अनेक objects बनवता येतात.
Q2. self का लागतो, आणि तो का लिहायला विसरला जातो?
Ans: self म्हणजे “हा विशिष्ट object.” प्रत्येक instance method मध्ये पहिला parameter म्हणून तो लागतोच, कारण Python ला कळायला हवं की कोणत्या object वर काम करायचं आहे. सुरुवातीला विसरला जातो कारण तो implicitly (आपोआप) पास होतो, त्यामुळे तो “दिसत” नाही.
Q3. Encapsulation खरंच data पूर्णपणे लपवतं का?
Ans: नाही, पूर्णपणे नाही. Python मध्ये खरी “private” संकल्पना नाही — __balance सारखे attributes फक्त name-mangling मुळे थेट access करणं अवघड होतं, पण _ClassName__balance असं लिहून तांत्रिकदृष्ट्या access करता येतं. हे फक्त एक convention आणि best-practice आहे, कडक सुरक्षा नाही.
Q4. Multiple inheritance म्हणजे काय, आणि ती वापरावी का?
Ans: एक class एकापेक्षा जास्त parent classes कडून inherit करू शकतो. उदा. class C(A, B):. ही सुविधा आहे, पण जास्त वापरल्यास कोड गुंतागुंतीचा होतो (यालाच “Diamond Problem” म्हणतात) — त्यामुळे गरज असेल तेव्हाच वापरावी.


