2.1.12 · HinglishOOP Fundamentals

Polymorphism — duck typing, same interface different behavior

1,686 words8 min readRead in English

2.1.12 · Coding › OOP Fundamentals


Polymorphism KYA hai?

Do flavors hain jinhe tumhe apne dimag mein alag rakhna hai:

Kind Idea Python example
Subtype / inheritance Ek subclass parent method ko override karta hai Dog(Animal) speak() ko override karta hai
Duck typing Koi bhi object jo method rakhta ho woh kaam karta hai — koi inheritance ki zaroorat nahi kuch bhi jisme .speak() ho

Yeh Python mein kyun kaam karta hai? (First principles)

Toh Python mein polymorphism koi special feature nahi hai — yeh dynamic attribute lookup se naturally nikalta hai. Koi compile-time type contract satisfy karna nahi hai.


Isko kaise use karein — scratch se build karo

Sabse general, type-agnostic version se shuru karo (pure duck typing):

def make_it_speak(thing):
    return thing.speak()        # hum sirf yeh chahte hain: thing ke paas .speak() ho

Ab ise bahut saare "ducks" do:

class Dog:
    def speak(self): return "Woof"
 
class Cat:
    def speak(self): return "Meow"
 
class Robot:                      # Dog/Cat se bilkul related nahi
    def speak(self): return "Beep boop"
 
for t in (Dog(), Cat(), Robot()):
    print(make_it_speak(t))      # Woof / Meow / Beep boop

Inheritance wala flavor (override)

class Animal:
    def speak(self):
        raise NotImplementedError   # base "promise" karta hai interface ka
 
class Dog(Animal):
    def speak(self): return "Woof"  # override
 
class Cat(Animal):
    def speak(self): return "Meow"  # override
Figure — Polymorphism — duck typing, same interface different behavior

Worked Example 1 — Ek len-jaisa total cost

class Book:
    def __init__(self, price): self.price = price
 
class Cart:
    def __init__(self, items): self.items = items
    def total(self):
        return sum(i.price for i in self.items)

Yeh step kyun? total() Book ke liye kaam karta hai, lekin kisi bhi object ke liye jo .price attribute rakhta ho — ek Toy, ek Subscription, etc. Humne ek interface code kiya (has .price), koi type nahi.

Worked Example 2 — Polymorphic area()

import math
class Circle:
    def __init__(self, r): self.r = r
    def area(self): return math.pi * self.r**2
 
class Square:
    def __init__(self, s): self.s = s
    def area(self): return self.s**2
 
def total_area(shapes):
    return sum(s.area() for s in shapes)
 
total_area([Circle(1), Square(2)])   # π·1² + 2² = π + 4 ≈ 7.1416

Yeh step kyun? total_area ek baar likha jaata hai. Same call s.area() circle ke liye run karta hai aur square ke liye same interface, different behavior. Baad mein Triangle add karo → total_area mein zero changes.

Worked Example 3 — Built-in polymorphism (+)

1 + 2          # 3        (int.__add__)
"a" + "b"      # "ab"     (str.__add__)
[1] + [2]      # [1, 2]   (list.__add__)

Yeh step kyun? + same operator name hai jo alag-alag type ke liye alag __add__ ko dispatch karta hai. Yahi operator polymorphism hai — Python ka syntax bhi duck-typed hai (yeh bas __add__ call karta hai).



Recall Feynman: 12 saal ke bacche ko samjhao

Socho ek TV remote hai jisme ek bada lal "GO" button hai. Car remote par press karo → car chalta hai. Wohi button drone remote par press karo → drone udta hai. Same button, alag machine, alag result. Tumhe yeh nahi jaanna ki machine andar se kaise kaam karti hai — bas GO press karo aur woh apna kaam karti hai. Code mein, "GO" method name hai jaise speak(), aur machine object hai. Jab tak kisi machine ke paas GO button hai, tumhara remote uske saath kaam karta hai — chahe kal koi brand-new toy kyun na invent ho.



Flashcards

"Polymorphism" ka literal translation kya hai?
"Bahut saare forms" — ek interface, bahut saare behaviors.
Duck typing ko ek line mein define karo.
Agar kisi object ke paas woh method/attribute hai jo tum use karo, toh woh kaam karta hai — Python behavior check karta hai, class nahi.
Kya Python ko polymorphism ke liye inheritance chahiye?
Nahi. Duck typing ko koi shared base class nahi chahiye; method lookup runtime par dynamic hota hai.
x.foo() call karne par runtime mein kya hota hai?
Python foo ko type(x).__mro__ ke zariye dhundhta hai; pehla mila woh call karta hai, nahi toh AttributeError raise hota hai.
Polymorphism ke liye har jagah isinstance check karna anti-pattern kyun hai?
Yeh naye compatible types ko reject karta hai, extensibility tod deta hai; EAFP / hasattr capability checks prefer karo.
Polymorphism ke do flavors bolo.
Subtype (inheritance + override) aur duck typing (interface-based, koi inheritance nahi).
+ polymorphism ka example kyun hai?
Same operator alag-alag type ke liye alag __add__ ko dispatch karta hai (int add karta hai, str/list concatenate karte hain).
Parent method ko override karne aur overwrite karne mein kya fark hai?
Override sirf us subclass ke lookup ko affect karta hai; parent aur siblings apna khud ka version rakhte hain.
EAFP ka matlab kya hai?
Easier to Ask Forgiveness than Permission — bas call karo, agar fail ho toh error catch karo.
total_area(shapes) ek baar likhna baad mein invent hone wali shapes ko kyun support karta hai?
Yeh sirf .area() interface par rely karta hai, toh koi bhi future object jo area() rakhta ho bina kisi change ke plug in ho jaata hai.

Connections

  • Inheritance — overriding and super()
  • Abstraction — interfaces and abstract base classes (ABC)
  • Dunder methods — __add__, __len__, __str__
  • Method Resolution Order (MRO)
  • EAFP vs LBYL — Pythonic error handling
  • Encapsulation — bundling data and behavior
  • Liskov Substitution Principle (SOLID)

Concept Map

means

enabled by

walks

not found

has flavor

has flavor

uses

needs inheritance

checks

falls out of

gives

no inheritance needed

Polymorphism

One interface many behaviors

Dynamic attribute lookup

MRO method lookup

Subtype polymorphism

Duck typing

Override parent method

Implicit interface .speak

Extensibility without rewrite

AttributeError if missing