# "If it walks like a duck and quacks like a duck..."
class Duck:
def speak(self):
return 'Quack!'
class Robot:
def speak(self):
return 'Beep boop!'
class Parrot:
def talk(self): # Different method name!
return 'Polly wants cracker'
def make_sound(obj):
# No type check — just call .speak()
# Will fail for Parrot (no .speak method)
return obj.speak()
print(make_sound(Duck())) # 'Quack!'
print(make_sound(Robot())) # 'Beep boop!'
# make_sound(Parrot()) # AttributeError!class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
class Rectangle:
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
class Triangle:
def __init__(self, base, height):
self.base, self.height = base, height
def area(self):
return 0.5 * self.base * self.height
# Same interface, different behavior
shapes = [Circle(5), Rectangle(4, 6), Triangle(3, 8)]
for s in shapes:
print(f'{s.__class__.__name__}: {s.area():.2f}')print(5 + 3) # 8 (int addition)
print('a' + 'b') # 'ab' (string concatenation)
print([1] + [2]) # [1, 2] (list concatenation)
print(3.14 * 2) # 6.28 (float multiplication)
print('ha' * 3) # 'hahaha' (string repetition)from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
# shape = Shape() # TypeError! Can't instantiate ABC
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
def perimeter(self):
return 4 * self.side
# Missing perimeter() would raise TypeError at import timeCreate a `PaymentProcessor` ABC with abstract method `pay(amount)`. Create `CreditCardPayment`, `PaypalPayment`, and `CryptoPayment` classes that implement `pay()` with unique messages. Write a `process_payment(processor, amount)` function that calls `processor.pay(amount)`. Demonstrate processing the same amount through all three.