Lesson ১২৮ মিনিট পড়া

ক্লাস এবং ওওপি (Classes & OOP)

সুপারপাওয়ারসহ আপনার নিজস্ব ডেটা টাইপ তৈরি করুন

ক্লাস কী? (What Are Classes?)

ক্লাস হলো একটি কুকি কাটারের (Cookie Cutter) মতো। কুকি কাটার নিজে কখনো কোনো কুকি বা বিস্কুট নয় — এটি কুকি তৈরি করার জন্য একটি টেমপ্লেট (ছাঁচ)। আপনি এই ছাঁচ দিয়ে যে নতুন কুকিগুলো তৈরি করবেন তার প্রতিটি হলো একেকটি অবজেক্ট (object) (যাকে ইনস্ট্যান্স বা instance-ও বলা হয়)। প্রতিটি কুকির আকার একই, তবে আপনি সেগুলোকে আলাদাভাবে সাজাতে পারেন (আলাদা আলাদা অ্যাট্রিবিউট ব্যবহার করে)।

প্রোগ্রামিংয়ের ভাষায়:

  • ক্লাস (Class) = একটি ব্লুপ্রিন্ট বা নকশা (কোনো কিছুর কী ডেটা এবং আচরণ থাকবে তা ঠিক করে দেয়)
  • অবজেক্ট/ইনস্ট্যান্স (Object/Instance) = সেই নকশা থেকে তৈরি একটি নির্দিষ্ট জিনিস
  • অ্যাট্রিবিউট (Attributes) = অবজেক্টে সংরক্ষণ করে রাখা ডেটা (যেমন name, age)
  • মেথড (Methods) = অবজেক্টের নিজস্ব ফাংশন (যেমন speak(), jump())

আপনার প্রথম ক্লাস (Your First Class)

class Dog:
# Class attribute (shared by ALL dogs)
species = "Canis familiaris"
def __init__(self, name, breed, age):
# Instance attributes (unique to each dog)
self.name = name
self.breed = breed
self.age = age
self.tricks = [] # Each dog starts with no tricks
def bark(self):
return f"{self.name} says: Woof!"
def learn_trick(self, trick):
self.tricks.append(trick)
return f"{self.name} learned {trick}!"
# Create instances (objects)
buddy = Dog("Buddy", "Golden Retriever", 3)
max_dog = Dog("Max", "German Shepherd", 5)
print(buddy.bark())
print(max_dog.bark())
print(buddy.learn_trick("shake"))
print(buddy.learn_trick("roll over"))
print(f"{buddy.name}'s tricks: {buddy.tricks}")
print(f"{max_dog.name}'s tricks: {max_dog.tricks}") # Still empty!
Output
Buddy says: Woof!
Max says: Woof!
Buddy learned shake!
Buddy learned roll over!
Buddy's tricks: ['shake', 'roll over']
Max's tricks: []

self প্যারামিটার (The self Parameter)

ক্লাসের প্রতিটি মেথড self-কে তার প্রথম প্যারামিটার হিসেবে গ্রহণ করে। self-কে একটি আয়নার (mirror) মতো চিন্তা করুন — এটি অবজেক্টকে নিজেকে নিজে রেফার (refer) করার সুযোগ করে দেয়। যখন আপনি buddy.bark() কল করেন, তখন পাইথন গোপনে self হিসেবে buddy-কে পাস করে, যার ফলে মেথডটি বুঝতে পারে যে কোন কুকুরটি ঘেউ ঘেউ করছে।

__init__ মেথডটি হলো একটি কনস্ট্রাক্টর (constructor) — যখনই আপনি একটি নতুন অবজেক্ট তৈরি করেন, তখন এটি স্বয়ংক্রিয়ভাবে রান করে। এটি হলো সেই জায়গা যেখানে আপনি অবজেক্টের শুরুর অবস্থাটি (starting state) সেটআপ করেন।

স্পেশাল (ডান্ডার) মেথডগুলো (Special (Dunder) Methods)

পাইথনে ডাবল আন্ডারস্কোর দিয়ে মোড়ানো বিশেষ মেথড ("ডান্ডার" বা dunder মেথড) আছে, যা আপনার অবজেক্টগুলোকে পাইথনের বিল্ট-ইন অপারেশন যেমন print(), len(), +, এবং বিভিন্ন তুলনামূলক কাজের সাথে ব্যবহার করার সুযোগ দেয়।

  • __str__print() এবং str() যা ব্যবহার করে। আপনার অবজেক্টকে মানুষের পড়ার উপযোগী করে তুলুন।
  • __repr__ — "ডেভেলপার" ভিউ। এটি আদর্শভাবে দেখানো উচিত যে কীভাবে অবজেক্টটিকে আবার তৈরি করা যায়।
  • __len__len(obj)-কে কাজ করতে দেয়।
  • __eq__ — আপনার অবজেক্টের জন্য == এর মানে কী, তা ঠিক করে।

ডান্ডার মেথডগুলোর ব্যবহার (Dunder Methods in Action)

class ShoppingCart:
def __init__(self):
self.items = []
def add(self, item, price):
self.items.append({"item": item, "price": price})
@property
def total(self):
return sum(i["price"] for i in self.items)
def __str__(self):
lines = [f" {i['item']}: ${i['price']:.2f}" for i in self.items]
return "Shopping Cart:\n" + "\n".join(lines) + f"\n Total: ${self.total:.2f}"
def __len__(self):
return len(self.items)
def __contains__(self, item_name):
return any(i["item"] == item_name for i in self.items)
cart = ShoppingCart()
cart.add("Coffee", 4.50)
cart.add("Muffin", 3.25)
cart.add("Juice", 5.00)
print(cart) # Uses __str__
print(f"Items: {len(cart)}") # Uses __len__
print(f"Has Coffee: {'Coffee' in cart}") # Uses __contains__
Output
Shopping Cart:
  Coffee: $4.50
  Muffin: $3.25
  Juice: $5.00
  Total: $12.75
Items: 3
Has Coffee: True

ইনহেরিটেন্স — যা আছে তার ওপরেই তৈরি করুন (Inheritance — Building on What Exists)

ইনহেরিটেন্স বা উত্তরাধিকার আপনাকে বিদ্যমান একটি ক্লাসের ওপর ভিত্তি করে একটি নতুন ক্লাস তৈরি করার সুযোগ দেয়। নতুন ক্লাসটি (চাইল্ড বা সন্তান) বিদ্যমান ক্লাসটির (প্যারেন্ট বা পিতামাতা) সমস্ত অ্যাট্রিবিউট এবং মেথড পায়, এবং সেটিতে নতুন কোনো কিছু যোগ করতে বা আগেরগুলোকে ওভাররাইড করতে পারে।

এটিকে একটি ফ্যামিলি বিজনেস বা পারিবারিক ব্যবসার মতো চিন্তা করুন: সন্তান বাবা-মায়ের রেসিপি (মেথড) এবং তৈরির উপাদানগুলোর (অ্যাট্রিবিউট) উত্তরাধিকারী হয়, তবে তারা নিজেদের নতুন স্পেশালিটি বা বিশেষত্বও তৈরি করতে পারে।

ইনহেরিটেন্স এবং super() (Inheritance & super())

class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def speak(self):
return f"{self.name} says {self.sound}!"
def __str__(self):
return f"{self.name} the {self.__class__.__name__}"
class Cat(Animal):
def __init__(self, name, indoor=True):
super().__init__(name, "Meow") # Call parent's __init__
self.indoor = indoor
def purr(self): # New method, only for cats
return f"{self.name} purrs softly..."
class Parrot(Animal):
def __init__(self, name, vocabulary=None):
super().__init__(name, "Squawk")
self.vocabulary = vocabulary or []
def speak(self): # Override parent method
if self.vocabulary:
import random
word = random.choice(self.vocabulary)
return f"{self.name} says: '{word}'"
return super().speak() # Fall back to parent
# Create instances
whiskers = Cat("Whiskers")
polly = Parrot("Polly", ["Hello!", "Pretty bird!", "Want a cracker?"])
print(whiskers.speak()) # Inherited from Animal
print(whiskers.purr()) # Cat-only method
print(polly.speak()) # Overridden method
print()
# isinstance checks
print(f"Is Whiskers an Animal? {isinstance(whiskers, Animal)}")
print(f"Is Polly a Cat? {isinstance(polly, Cat)}")
Output
Whiskers says Meow!
Whiskers purrs softly...
Polly says: 'Hello!'

Is Whiskers an Animal? True
Is Polly a Cat? False
Note: নতুনদের একটি সাধারণ ভুল: চাইল্ড ক্লাসে super().__init__() কল করতে ভুলে যাওয়া। এটি ছাড়া, প্যারেন্ট বা পিতামাতা ক্লাসের সেটআপ কোডটি রান করে না এবং আপনার অবজেক্টে বেশ কিছু অ্যাট্রিবিউট মিসিং থাকবে। আপনার চাইল্ডের __init__-এ সব সময় সবার আগে super() কল করুন!
চ্যালেঞ্জ

ছোট কুইজ

যেকোনো মেথডে self বলতে কী বোঝায়?
Error HandlingModules & Imports