प्रस्तावना (Introduction)
जेव्हा मी पहिल्यांदा Python शिकायला सुरुवात केली, तेव्हा functions आणि loops पर्यंत सगळं ठीक चाललं होतं. पण जेव्हा OOP (Object Oriented Programming) आलं, तेव्हा खरा गोंधळ सुरू झाला. “class म्हणजे काय?”, “object आणि class मध्ये फरक काय?”, “self का लिहायचं?” — हे प्रश्न मला आठवडाभर छळत होते.
आज लिहितोय ते फक्त textbook definitions नाहीत — तर मी स्वतः शिकताना जे कोड लिहिले, ज्या चुका केल्या, आणि ज्या error screenshots आले, त्या सगळ्यांसह हा blog आहे. त्यामुळे तुम्हाला हे फक्त “वाचायला” नाही, तर प्रत्यक्ष अनुभवातून शिकायला मिळेल. चला सुरुवात करूया.
Table of Contents
OOP म्हणजे नक्की काय? (What is OOP?)
Object Oriented Programming ही एक अशी पद्धत आहे जिथे आपण आपला कोड real-world वस्तूंसारखा (objects) organize करतो. उदाहरणार्थ — एक “कुत्रा” (Dog) ही वस्तू आहे. त्याचं नाव आहे, वय आहे (हे झालं data/attributes), आणि तो भुंकू शकतो, धावू शकतो (हे झालं behavior/methods).
Python मध्ये OOP चे चार मुख्य स्तंभ (Four Pillars) आहेत:
- Inheritance (वारसा)
- Polymorphism (बहुरूपता)
- Encapsulation (संकलन)
- Abstraction (अमूर्तीकरण)
पण त्याआधी आपल्याला Class आणि Object समजून घ्यावे लागतील, कारण संपूर्ण OOP याच दोन गोष्टींवर उभं आहे.
Class म्हणजे काय? (What is a Class?)
Class ही एक blueprint किंवा साचा आहे. जसं घर बांधण्याआधी architect एक नकाशा (design) बनवतो, तसाच class एक टेम्पलेट असतो, ज्यावरून पुढे अनेक objects तयार करता येतात.
मी जेव्हा पहिल्यांदा class लिहिला, तेव्हा मी “Student” चं उदाहरण घेतलं होतं, कारण मला ते जवळचं वाटलं:
class Student:
school_name = "Zilla Parishad Shala" # Class attribute
def __init__(self, name, marks):
self.name = name # Instance attribute
self.marks = marks # Instance attribute
def result(self):
if self.marks >= 35:
return f"{self.name} पास झाला/झाली आहे."
else:
return f"{self.name} नापास झाला/झाली आहे."इथे काय होतंय ते समजून घेऊ:
class Student:— यामुळे Student नावाचा एक नवीन class तयार होतो.school_nameहे एक class attribute आहे — म्हणजे या class पासून बनणाऱ्या प्रत्येक object ला हे common असेल.__init__()ही एक विशेष method आहे, जिला constructor म्हणतात. जेव्हा तुम्ही नवीन object तयार करता, तेव्हा ही method आपोआप चालते.selfम्हणजे “सध्याचा object स्वतः.” प्रत्येक object ला त्याचा स्वतःचा data ठेवण्यासाठीselfलागतो.
माझी पहिली चूक — self विसरणे:
जेव्हा मी सुरुवातीला हा कोड लिहीत होतो, तेव्हा मी चुकून self parameter द्यायला विसरलो:
class Student:
def __init__(name, marks): # चुकीचं — self नाही!
self.name = name
self.marks = marksआणि जेव्हा मी object तयार केला:
s1 = Student("Amit", 78)तेव्हा मला हा error आला: TypeError: init() takes 2 positional arguments but 3 were given
हा error का येतो? ,कारण Python आपोआप पहिला argument म्हणून object स्वतः (self) पाठवतं. जर तुम्ही self लिहायला विसरलात, तर Python ला वाटतं की तुम्ही जास्तीचा argument दिला आहे. ही चूक जवळपास प्रत्येक नवशिक्या करतो — त्यामुळे लक्षात ठेवा: पहिला parameter नेहमी self असतो
Object म्हणजे काय? (What is an Object?)
Object हा class चा actual instance आहे. म्हणजे class हा फक्त नकाशा होता, आणि object म्हणजे त्या नकाशावरून प्रत्यक्ष बांधलेलं घर.
s1 = Student("Amit", 78)
s2 = Student("Sneha", 32)
print(s1.result())
print(s2.result())Amit पास झाला/झाली आहे. Sneha नापास झाला/झाली आहे.
लक्षात घ्या.s1 आणि s2 हे दोन वेगळे objects आहेत. प्रत्येकाचा स्वतःचा name आणि marks आहे, पण दोघेही एकाच Student class वरून बनलेले आहेत.
एका object कडे तीन गोष्टी असतात:
- State: attributes मधून दिसणारा data (उदा. name, marks)
- Behavior: methods मधून दिसणारं वर्तन (उदा. result())
- Identity: प्रत्येक object हा वेगळा असतो, जरी data सारखा असला तरी
4 OOP Concept
1. Inheritance (वारसा):
Inheritance म्हणजे एक class दुसऱ्या class चे गुणधर्म आणि methods घेऊ शकते. यामुळे code reuse होतो, तेच तेच लिहावं लागत नाही.
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} जेवत आहे.")
class Dog(Animal): # Dog class Animal कडून inherit करतो
def bark(self):
print(f"{self.name} भुंकत आहे.")
d1 = Dog("Tommy")
d1.eat() # Animal class ची method
d1.bark() # Dog class ची स्वतःची methodTommy जेवत आहे. Tommy भुंकत आहे.
इथे Dog ला eat() परत लिहावं लागलं नाही, कारण ते आधीच Animal class मध्ये आहे. हेच खरं code reusability चं उदाहरण.
2. Polymorphism (बहुरूपता):
Polymorphism म्हणजे “एकच नाव, वेगवेगळं वर्तन.” म्हणजे एकाच method चं नाव वेगवेगळ्या classes मध्ये वेगळ्या पद्धतीने काम करू शकतं.
class Cat:
def sound(self):
print("मांजर 'म्याव' करते")
class Cow:
def sound(self):
print("गाय 'हंबरते'")
for animal in (Cat(), Cow()):
animal.sound()मांजर 'म्याव' करते गाय 'हंबरते'
दोन्ही classes मध्ये sound() हे नाव सारखंच आहे, पण वर्तन वेगळं आहे, हेच polymorphism.
3. Encapsulation (संकलन)
Encapsulation म्हणजे data आणि त्यावर काम करणाऱ्या methods यांना एकत्र बांधून ठेवणं, आणि काही data बाहेरून directly बदलता येऊ नये यासाठी नियंत्रण ठेवणं.
class BankAccount:
def __init__(self, balance):
self.__balance = balance # double underscore = private
def deposit(self, amount):
self.__balance += amount
def show_balance(self):
print(f"सध्याची शिल्लक: {self.__balance}")
acc = BankAccount(1000)
acc.deposit(500)
acc.show_balance()Output: सध्याची शिल्लक: 1500
माझी दुसरी चूक — private variable थेट access करण्याचा प्रयत्न मी सुरुवातीला असं लिहिलं होतं: print(acc.__balance)
आणि मला हा error मिळाला: AttributeError: ‘BankAccount’ object has no attribute ‘__balance’
याचं कारण असं की __balance सारखे double-underscore attributes Python मध्ये name mangling मुळे बाहेरून direct access करता येत नाहीत. हाच तर encapsulation चा उद्देश आहे — डेटा सुरक्षित ठेवणं, आणि तो फक्त class च्या आतल्या methods मधूनच बदलता यावा.
4. Data Abstraction (अमूर्तीकरण)
Abstraction म्हणजे “काय होतंय” हे दाखवणं, पण “कसं होतंय” ते लपवणं. उदाहरणार्थ, तुम्ही bike चालवताना फक्त accelerator आणि brake वापरता — इंजिन आतून कसं काम करतं हे तुम्हाला माहीत असण्याची गरज नसते.
from abc import ABC, abstractmethod
class Vehicle(ABC):
@abstractmethod
def start_engine(self):
pass
class Bike(Vehicle):
def start_engine(self):
print("बाईकचं इंजिन सुरू झालं.")
b = Bike()
b.start_engine()Output: बाईकचं इंजिन सुरू झालं.
हे सगळे concepts एकत्र वापरून एक Mini Project
खाली एक छोटं उदाहरण आहे जे मी स्वतः सराव करताना बनवलं होतं, Library Management चा एक छोटा भाग:
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
self.is_issued = False
def issue_book(self):
if not self.is_issued:
self.is_issued = True
print(f"'{self.title}' पुस्तक issue झालं.")
else:
print(f"'{self.title}' आधीच issue केलेलं आहे.")
b1 = Book("Python पूर्ण मार्गदर्शक", "Rupesh Pawar")
b1.issue_book()
b1.issue_book()Output:
‘Python पूर्ण मार्गदर्शक’ पुस्तक issue झालं.
‘Python पूर्ण मार्गदर्शक’ आधीच issue केलेलं आहे.
हा एक साधा पण practical उदाहरण आहे जो दाखवतो की class, object, आणि methods एकत्र कसे काम करतात.
super() आणि Method Overriding
Inheritance शिकताना एक गोष्ट पुढे नक्की लागते, method overriding. म्हणजे child class ने parent class ची method स्वतःच्या पद्धतीने पुन्हा लिहिणं.
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
print(f"{self.name} काहीतरी आवाज करतो.")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # parent class चा constructor call
self.breed = breed
def make_sound(self): # overriding
print(f"{self.name} (जात: {self.breed}) भुंकतो.")
d = Dog("Bruno", "Labrador")
d.make_sound()Output: Bruno (जात: Labrador) भुंकतो.
super() वापरल्यामुळे मला parent class चा __init__ पुन्हा लिहावा लागला नाही — फक्त नवीन गोष्ट (breed) जोडली. सुरुवातीला मी super().__init__(name) ऐवजी थेट Animal.__init__(self, name) असं लिहायचो — दोन्ही चालतं, पण super() वापरणं जास्त clean आणि maintainable मानलं जातं, विशेषतः जेव्हा multiple inheritance असते.
Class Method आणि Static Method – फरक काय?
बऱ्याच tutorials मध्ये हे टाळलं जातं, पण practical कोड लिहिताना हे नक्की लागतं.
class Employee:
company_name = "lgrow.in"
def __init__(self, name):
self.name = name
@classmethod
def change_company(cls, new_name):
cls.company_name = new_name
@staticmethod
def is_valid_age(age):
return age >= 18
print(Employee.is_valid_age(20)) # True
Employee.change_company("Lgrow Technologies")
print(Employee.company_name) # Lgrow TechnologiesOutput: True
Lgrow Technologies
@classmethod— पहिला parameterclsघेतो, आणि class-level data बदलण्यासाठी वापरला जातो.@staticmethod— नाselfघेतो नाcls. जेव्हा एखादी utility function class च्या आत ठेवायची असते, पण त्याला object किंवा class च्या data ची गरज नसते, तेव्हा static method वापरतात.
मी सुरुवातीला या दोघांमध्ये गोंधळून जायचो — पण साधा नियम लक्षात ठेवा: जर तुम्हाला class चा data बदलायचा आहे, तर classmethod; जर फक्त logic हवं आहे data शिवाय, तर staticmethod.
Encapsulation आणि Abstraction – नेहमी होणारा गोंधळ
बऱ्याच नवशिक्यांना (मला सुद्धा सुरुवातीला) हे दोन concepts सारखेच वाटतात — कारण दोघांचाही उद्देश “काहीतरी लपवणं” असा दिसतो. पण प्रत्यक्षात फरक असा आहे:
- Encapsulation: कसं लपवायचं याबद्दल आहे. म्हणजे data आणि methods एकत्र बांधून, आणि access control (private/protected) वापरून डेटा सुरक्षित ठेवणं.
- Abstraction: काय दाखवायचं याबद्दल आहे. म्हणजे वापरकर्त्याला फक्त गरजेचं interface दाखवणं, आतलं implementation लपवणं.
सोप्या शब्दांत, Encapsulation ही design ची पद्धत आहे (data कसा ठेवायचा), तर Abstraction ही design ची विचारसरणी आहे (काय दाखवायचं, काय नाही). ATM मशीनचं उदाहरण घेतलं तर — तुम्हाला फक्त “पैसे काढा” हे बटण दिसतं (abstraction), पण त्यामागचा बँकेचा database, security checks हे सगळं तुमच्यापासून लपवलेलं आणि सुरक्षित ठेवलेलं असतं (encapsulation).
OOP प्रत्यक्ष कुठे वापरतात? (Real-World Use Cases)
Tutorial मध्ये उदाहरणं दिली की गोष्टी सोप्या वाटतात, पण खरं महत्त्व कळतं जेव्हा तुम्ही मोठे प्रोजेक्ट्स बघता:
- Django/Flask web development — प्रत्येक database table हा एक class असतो (Models), आणि प्रत्येक row हा एक object.
- Game development — प्रत्येक player, enemy, item हे एकेक class म्हणून तयार केले जातात.
- Automation scripts — उदा. WordPress साठी टूल्स बनवताना, प्रत्येक “task” (उदा. Error Decoder, Translator) एक class म्हणून organize केल्यास कोड जास्त readable राहतो.
lgrow.in वरचे इंटरॅक्टिव्ह टूल्स बनवतानाही मी हीच पद्धत वापरतो — प्रत्येक टूलचं लॉजिक वेगळ्या class मध्ये ठेवलं की debug करणं आणि नवीन features जोडणं खूप सोपं होतं.
Interview मध्ये विचारले जाणारे OOP प्रश्न
जर तुम्ही placement किंवा internship साठी तयारी करत असाल, तर खालील प्रश्न वारंवार विचारले जातात, मला स्वतः यापैकी दोन प्रश्न एका मुलाखतीत आले होते, आणि तेव्हा मला जाणवलं की फक्त definitions पाठ करून उपयोग नाही, तर प्रत्यक्ष कोड लिहून concept समजणं गरजेचं आहे.
1. Class आणि Structure (इतर भाषांमधलं) यात फरक काय?
Ans: Class मध्ये data बरोबर methods (behavior) सुद्धा असतात, तर struct मध्ये फक्त data असतो.
2. __init__ आणि __new__ यात फरक काय?
Ans: __new__ object प्रत्यक्ष तयार करतो (memory allocate करतो), तर __init__ तो object तयार झाल्यावर त्याचा data initialize करतो. बहुतांश वेळा फक्त __init__ सोबतच काम पुरतं.
3. Method Overloading Python मध्ये शक्य आहे का?
Ans: इतर भाषांप्रमाणे (Java/C++) थेट overloading Python मध्ये नाही, पण default parameters किंवा *args, **kwargs वापरून तसंच वर्तन मिळवता येतं.
4. Composition आणि Inheritance मध्ये फरक काय?
Ans: — Inheritance म्हणजे “is-a” relationship (उदा. Dog is an Animal), तर Composition म्हणजे “has-a” relationship (उदा. Car has an Engine — engine ही स्वतंत्र class असून Car मध्ये object म्हणून वापरली जाते).
Composition चं एक छोटं उदाहरण:
class Engine:
def start(self):
print("इंजिन सुरू झालं.")
class Car:
def __init__(self):
self.engine = Engine() # Composition — Car कडे Engine चं object आहे
def start_car(self):
self.engine.start()
print("गाडी सुरू झाली.")
my_car = Car()
my_car.start_car()Output: इंजिन सुरू झालं.
गाडी सुरू झाली.
बऱ्याचदा नवशिक्या फक्त Inheritance शिकून थांबतात, पण real projects मध्ये Composition जास्त वापरली जाते — कारण ती flexible असते आणि tightly-coupled classes टाळते.
वारंवार विचारले जाणारे प्रश्न (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” म्हणतात) — त्यामुळे गरज असेल तेव्हाच वापरावी.


