একাধিক সম্পর্কিত ক্লাস হয়ে গেলে এই দুটো ফিচারই ক্লাসকে সত্যিকারভাবে শক্তিশালী করে তোলে।
ইনহেরিটেন্স একটি ক্লাসকে আরেকটির উপর ভিত্তি করে তৈরি করতে দেয়, তার প্রপার্টি আর মেথড আবার না লিখে পুনঃব্যবহার করে — এর জন্য Python-এর সিনট্যাক্স হলো বন্ধনীতে parent ক্লাসের নাম বসানো:
class Person:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hi, I'm {self.name}."
class Student(Person):
def __init__(self, name, course):
super().__init__(name) # reuse Person's constructor
self.course = course
s = Student("Amit", "Graphic Design")
print(s.greet()) # "Hi, I'm Amit." — inherited from Person, unchangedsuper() হলো PHP-এর parent::-এর Python সমতুল্য — এটি একটি মেথডের parent ক্লাসের নিজস্ব ভার্সনে অ্যাক্সেস দেয়, সবচেয়ে বেশি এর __init__ পুনঃব্যবহার করতে ব্যবহৃত হয়।
পলিমরফিজম মানে ভিন্ন ভিন্ন ক্লাস একই মেথড নাম নিজেদের মতো করে কার্যকর করতে পারে, আর কল করা কোডকে জানতে হয় না ঠিক কোন ক্লাসের সাথে এটি কাজ করছে:
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
for animal in [Dog(), Cat()]:
print(animal.speak()) # "Woof!" then "Meow!" — same call, different behaviorলক্ষ্য করুন এখানে Dog আর Cat ইনহেরিটেন্স দিয়ে একদমই সম্পর্কিত নয় — এটা কাজ করতে Python-এর একটি শেয়ার করা parent ক্লাস বা ইন্টারফেসের দরকার নেই, PHP-এর থেকে আলাদা, যার একটি মেথড কল করার আগে সেটা আছে তা নিশ্চিত করতে একটি স্পষ্ট interface দরকার। এই বেশি নমনীয় স্টাইলকে প্রায়ই বলা হয় duck typing: "যদি এটা হাঁসের মতো হাঁটে আর হাঁসের মতো ডাকে" — একটি অবজেক্টের যদি একটি .speak() মেথড থাকে, Python খুশি মনে সেটা কল করবে, অবজেক্টের প্রকৃত ক্লাস যাই হোক না কেন।
print(isinstance(s, Student)) # True
print(isinstance(s, Person)) # True — Student is also a Person, via inheritance