OOP Intermediate
Inheritance
Extending Classes
You have Employee with name and salary. Manager needs the same plus a team list. Instead of duplicating code, Manager extends Employee - inheriting its attributes and methods while adding its own.
Basic inheritance
Create a subclass that extends a parent.
# Basic Inheritance
class Animal:
"""Base class for all animals."""
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
def describe(self):
return f"I am {self.name}"
# Dog inherits from Animal
class Dog(Animal):
"""Dog class inherits from Animal."""
pass # No additional code - inherits everything
# Cat inherits from Animal
class Cat(Animal):
"""Cat class inherits from Animal."""
pass
# Bird with additional attribute
class Bird(Animal):
def __init__(self, name, can_fly=True):
# Call parent's __init__
super().__init__(name)
self.can_fly = can_fly
# Demonstrate basic inheritance
print("=== Basic Inheritance ===\n")
# Create Dog - uses inherited __init__
dog = Dog("Buddy")
print(f"Dog name: {dog.name}")
print(f"Dog speaks: {dog.speak()}")
print(f"Dog describes: {dog.describe()}")
print()
# Create Cat - also inherits everything
cat = Cat("Whiskers")
print(f"Cat name: {cat.name}")
print(f"Cat speaks: {cat.speak()}")
print(f"Cat describes: {cat.describe()}")
print()
# Create Bird - has additional attribute
bird = Bird("Tweety")
print(f"Bird name: {bird.name}")
print(f"Bird can fly: {bird.can_fly}")
print(f"Bird speaks: {bird.speak()}")
print()
# Bird that can't fly
penguin = Bird("Pingu", can_fly=False)
print(f"Penguin name: {penguin.name}")
print(f"Penguin can fly: {penguin.can_fly}")
print("\n=== Inheritance Rules ===")
print("""
1. Child inherits all attributes and methods
2. Syntax: class Child(Parent):
3. super().__init__() calls parent's __init__
4. Child can add new attributes/methods
5. 'pass' means no additions (pure inheritance)
""")
# Basic Inheritance
class Animal:
"""Base class for all animals."""
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
def describe(self):
return f"I am {self.name}"
# Dog inherits from Animal
class Dog(Animal):
"""Dog class inherits from Animal."""
pass # No additional code - inherits everything
# Cat inherits from Animal
class Cat(Animal):
"""Cat class inherits from Animal."""
pass
# Bird with additional attribute
class Bird(Animal):
def __init__(self, name, can_fly=True):
# Call parent's __init__
super().__init__(name)
self.can_fly = can_fly
# Demonstrate basic inheritance
print("=== Basic Inheritance ===\n")
# Create Dog - uses inherited __init__
dog = Dog("Rex")
print(f"Dog name: {dog.name}")
print(f"Dog speaks: {dog.speak()}")
print(f"Dog describes: {dog.describe()}")
print()
# Create Cat - also inherits everything
cat = Cat("Whiskers")
print(f"Cat name: {cat.name}")
print(f"Cat speaks: {cat.speak()}")
print(f"Cat describes: {cat.describe()}")
print()
# Create Bird - has additional attribute
bird = Bird("Tweety")
print(f"Bird name: {bird.name}")
print(f"Bird can fly: {bird.can_fly}")
print(f"Bird speaks: {bird.speak()}")
print()
# Bird that can't fly
penguin = Bird("Pingu", can_fly=False)
print(f"Penguin name: {penguin.name}")
print(f"Penguin can fly: {penguin.can_fly}")
print("\n=== Inheritance Rules ===")
print("""
1. Child inherits all attributes and methods
2. Syntax: class Child(Parent):
3. super().__init__() calls parent's __init__
4. Child can add new attributes/methods
5. 'pass' means no additions (pure inheritance)
""")
# Basic Inheritance
class Animal:
"""Base class for all animals."""
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
def describe(self):
return f"I am {self.name}"
# Dog inherits from Animal
class Dog(Animal):
"""Dog class inherits from Animal."""
pass # No additional code - inherits everything
# Cat inherits from Animal
class Cat(Animal):
"""Cat class inherits from Animal."""
pass
# Bird with additional attribute
class Bird(Animal):
def __init__(self, name, can_fly=True):
# Call parent's __init__
super().__init__(name)
self.can_fly = can_fly
# Demonstrate basic inheritance
print("=== Basic Inheritance ===\n")
# Create Dog - uses inherited __init__
dog = Dog("Luna")
print(f"Dog name: {dog.name}")
print(f"Dog speaks: {dog.speak()}")
print(f"Dog describes: {dog.describe()}")
print()
# Create Cat - also inherits everything
cat = Cat("Whiskers")
print(f"Cat name: {cat.name}")
print(f"Cat speaks: {cat.speak()}")
print(f"Cat describes: {cat.describe()}")
print()
# Create Bird - has additional attribute
bird = Bird("Tweety")
print(f"Bird name: {bird.name}")
print(f"Bird can fly: {bird.can_fly}")
print(f"Bird speaks: {bird.speak()}")
print()
# Bird that can't fly
penguin = Bird("Pingu", can_fly=False)
print(f"Penguin name: {penguin.name}")
print(f"Penguin can fly: {penguin.can_fly}")
print("\n=== Inheritance Rules ===")
print("""
1. Child inherits all attributes and methods
2. Syntax: class Child(Parent):
3. super().__init__() calls parent's __init__
4. Child can add new attributes/methods
5. 'pass' means no additions (pure inheritance)
""")
# Basic Inheritance
class Animal:
"""Base class for all animals."""
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
def describe(self):
return f"I am {self.name}"
# Dog inherits from Animal
class Dog(Animal):
"""Dog class inherits from Animal."""
pass # No additional code - inherits everything
# Cat inherits from Animal
class Cat(Animal):
"""Cat class inherits from Animal."""
pass
# Bird with additional attribute
class Bird(Animal):
def __init__(self, name, can_fly=True):
# Call parent's __init__
super().__init__(name)
self.can_fly = can_fly
# Demonstrate basic inheritance
print("=== Basic Inheritance ===\n")
# Create Dog - uses inherited __init__
dog = Dog("Buddy")
print(f"Dog name: {dog.name}")
print(f"Dog speaks: {dog.speak()}")
print(f"Dog describes: {dog.describe()}")
print()
# Create Cat - also inherits everything
cat = Cat("Whiskers")
print(f"Cat name: {cat.name}")
print(f"Cat speaks: {cat.speak()}")
print(f"Cat describes: {cat.describe()}")
print()
# Create Bird - has additional attribute
bird = Bird("Robin")
print(f"Bird name: {bird.name}")
print(f"Bird can fly: {bird.can_fly}")
print(f"Bird speaks: {bird.speak()}")
print()
# Bird that can't fly
penguin = Bird("Pingu", can_fly=False)
print(f"Penguin name: {penguin.name}")
print(f"Penguin can fly: {penguin.can_fly}")
print("\n=== Inheritance Rules ===")
print("""
1. Child inherits all attributes and methods
2. Syntax: class Child(Parent):
3. super().__init__() calls parent's __init__
4. Child can add new attributes/methods
5. 'pass' means no additions (pure inheritance)
""")
# Basic Inheritance
class Animal:
"""Base class for all animals."""
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
def describe(self):
return f"I am {self.name}"
# Dog inherits from Animal
class Dog(Animal):
"""Dog class inherits from Animal."""
pass # No additional code - inherits everything
# Cat inherits from Animal
class Cat(Animal):
"""Cat class inherits from Animal."""
pass
# Bird with additional attribute
class Bird(Animal):
def __init__(self, name, can_fly=True):
# Call parent's __init__
super().__init__(name)
self.can_fly = can_fly
# Demonstrate basic inheritance
print("=== Basic Inheritance ===\n")
# Create Dog - uses inherited __init__
dog = Dog("Buddy")
print(f"Dog name: {dog.name}")
print(f"Dog speaks: {dog.speak()}")
print(f"Dog describes: {dog.describe()}")
print()
# Create Cat - also inherits everything
cat = Cat("Whiskers")
print(f"Cat name: {cat.name}")
print(f"Cat speaks: {cat.speak()}")
print(f"Cat describes: {cat.describe()}")
print()
# Create Bird - has additional attribute
bird = Bird("Kiwi", can_fly=False)
print(f"Bird name: {bird.name}")
print(f"Bird can fly: {bird.can_fly}")
print(f"Bird speaks: {bird.speak()}")
print()
# Bird that can't fly
penguin = Bird("Pingu", can_fly=False)
print(f"Penguin name: {penguin.name}")
print(f"Penguin can fly: {penguin.can_fly}")
print("\n=== Inheritance Rules ===")
print("""
1. Child inherits all attributes and methods
2. Syntax: class Child(Parent):
3. super().__init__() calls parent's __init__
4. Child can add new attributes/methods
5. 'pass' means no additions (pure inheritance)
""")
"""Base class for all animals."""
3class Animal: #?animalclass4 """Base class for all animals."""5 6 def __init__(self, name): #?initmethod7 self.name = name #?storename8 9 def speak(self): #?speakmethod10 return f"{self.name} makes a sound"11 12 def describe(self): #?describemethod13 return f"I am {self.name}"141516# Dog inherits from Animal #?dogclass17class Dog(Animal): #?dogdefinition18 """Dog class inherits from Animal."""19 pass # No additional code - inherits everything #?passstatement202122# Cat inherits from Animal23class Cat(Animal): #?catclass24 """Cat class inherits from Animal."""25 pass262728# Bird with additional attribute #?birdclass29class Bird(Animal): #?birddefinition30 def __init__(self, name, can_fly=True): #?birdinitn31 # Call parent's __init__ #?callsuper32 super().__init__(name) #?superinit33 self.can_fly = can_fly #?extraattribute343536# Demonstrate basic inheritance37print("=== Basic Inheritance ===\n")3839# Create Dog - uses inherited __init__ #?createdog40dog = Dog("Buddy") #?doginstance41#@dog=Dog("Rex"), Dog("Luna")output=== Basic Inheritance ===self.name ← Buddy
pass 1 of 46def __init__(self⟨Dog A⟩, nameBuddy): #?initmethod7 self.name→ Buddy = nameBuddy #?storenameAll 4 passes — pass 1 is the card above pass selfnameself.name1 ⟨Dog A⟩ Buddy Buddy 2 ⟨Cat B⟩ Whiskers Whiskers 3 ⟨Bird C⟩ Tweety Tweety 4 ⟨Bird D⟩ Pingu Pingu dog ← ⟨Dog A⟩
39# Create Dog - uses inherited __init__ #?createdog40dog→ ⟨Dog A⟩ = Dog("Buddy") #?doginstance41#@dog=Dog("Rex"), Dog("Luna")42print(f"Dog name: {dog.nameBuddy}") #?accessattribute43print(f"Dog speaks: {dog⟨Dog A⟩.speak()}") #?callmethod44print(f"Dog describes: {dog.describe()}")outputDog name: Buddydef speak(self): #?speakmethod
pass 1 of 39def speak(self⟨Dog A⟩): #?speakmethod10 return f"{self.nameBuddy} makes a sound"All 3 passes — pass 1 is the card above pass selfself.name1 ⟨Dog A⟩ Buddy 2 ⟨Cat B⟩ Whiskers 3 ⟨Bird C⟩ Tweety print(f"Dog speaks: {dog.speak()}") #?callmethod
42print(f"Dog name: {dog.name}") #?accessattribute43print(f"Dog speaks: {dog⟨Dog A⟩.speak()}") #?callmethod44print(f"Dog describes: {dog⟨Dog A⟩.describe()}")outputDog speaks: Buddy makes a sounddef describe(self): #?describemethod
pass 1 of 212def describe(self⟨Dog A⟩): #?describemethod13 return f"I am {self.nameBuddy}"print(f"Dog describes: {dog.describe()}")
43print(f"Dog speaks: {dog.speak()}") #?callmethod44print(f"Dog describes: {dog⟨Dog A⟩.describe()}")4546print()4748# Create Cat - also inherits everything #?createcat49cat = Cat("Whiskers")50print(f"Cat name: {cat.name}")outputDog describes: I am Buddycat ← ⟨Cat B⟩
48# Create Cat - also inherits everything #?createcat49cat→ ⟨Cat B⟩ = Cat("Whiskers")50print(f"Cat name: {cat.nameWhiskers}")51print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")52print(f"Cat describes: {cat.describe()}")outputCat name: Whiskersprint(f"Cat speaks: {cat.speak()}")
50print(f"Cat name: {cat.name}")51print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")52print(f"Cat describes: {cat⟨Cat B⟩.describe()}")outputCat speaks: Whiskers makes a sounddef describe(self): #?describemethod
pass 2 of 212def describe(self⟨Cat B⟩): #?describemethod13 return f"I am {self.nameWhiskers}"print(f"Cat describes: {cat.describe()}")
51print(f"Cat speaks: {cat.speak()}")52print(f"Cat describes: {cat⟨Cat B⟩.describe()}")5354print()5556# Create Bird - has additional attribute #?createbird57bird = Bird("Tweety") #?birdinstance58#@bird=Bird("Robin"), Bird("Kiwi", can_fly=False)outputCat describes: I am Whiskersdef __init__(self, name, can_fly=True): #?birdinitn # Call par…
pass 1 of 229class Bird(Animal): #?birddefinition30 def __init__(self⟨Bird C⟩, nameTweety, can_flyTrue=TrueTrue): #?birdinitn31 # Call parent's __init__ #?callsuper32 super().__init__(name) #?superinit33 self.can_fly = can_fly #?extraattributeself.can_fly ← True
32super().__init__(name) #?superinit33self.can_fly→ True = can_flyTrue #?extraattributebird ← ⟨Bird C⟩
56# Create Bird - has additional attribute #?createbird57bird→ ⟨Bird C⟩ = Bird("Tweety") #?birdinstance58#@bird=Bird("Robin"), Bird("Kiwi", can_fly=False)59print(f"Bird name: {bird.nameTweety}")60print(f"Bird can fly: {bird.can_flyTrue}")61print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")outputBird name: Tweety Bird can fly: Trueprint(f"Bird speaks: {bird.speak()}")
60print(f"Bird can fly: {bird.can_fly}")61print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")6263print()6465# Bird that can't fly #?flightlessbird66penguin = Bird("Pingu", can_fly=False) #?penguininstance67print(f"Penguin name: {penguin.name}")outputBird speaks: Tweety makes a sounddef __init__(self, name, can_fly=True): #?birdinitn # Call par…
pass 2 of 229class Bird(Animal): #?birddefinition30 def __init__(self⟨Bird D⟩, namePingu, can_flyFalse=TrueTrue): #?birdinitn31 # Call parent's __init__ #?callsuper32 super().__init__(name) #?superinit33 self.can_fly = can_fly #?extraattributeself.can_fly ← False
32super().__init__(name) #?superinit33self.can_fly→ False = can_flyFalse #?extraattributepenguin ← ⟨Bird D⟩
65# Bird that can't fly #?flightlessbird66penguin→ ⟨Bird D⟩ = Bird("Pingu", can_fly=False) #?penguininstance67print(f"Penguin name: {penguin.namePingu}")68print(f"Penguin can fly: {penguin.can_flyFalse}")6970print("\n=== Inheritance Rules ===")71print("""721. Child inherits all attributes and methods732. Syntax: class Child(Parent):743. super().__init__() calls parent's __init__754. Child can add new attributes/methods765. 'pass' means no additions (pure inheritance)77""")outputPenguin name: Pingu Penguin can fly: False === Inheritance Rules === 1. Child inherits all attributes and methods 2. Syntax: class Child(Parent): 3. super().__init__() calls parent's __init__ 4. Child can add new attributes/methods 5. 'pass' means no additions (pure inheritance)
"""Base class for all animals."""
3class Animal:4 """Base class for all animals."""5 6 def __init__(self, name):7 self.name = name8 9 def speak(self):10 return f"{self.name} makes a sound"11 12 def describe(self):13 return f"I am {self.name}"141516# Dog inherits from Animal17class Dog(Animal):18 """Dog class inherits from Animal."""19 pass # No additional code - inherits everything202122# Cat inherits from Animal23class Cat(Animal):24 """Cat class inherits from Animal."""25 pass262728# Bird with additional attribute29class Bird(Animal):30 def __init__(self, name, can_fly=True):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_fly343536# Demonstrate basic inheritance37print("=== Basic Inheritance ===\n")3839# Create Dog - uses inherited __init__40dog = Dog("Rex")41print(f"Dog name: {dog.name}")output=== Basic Inheritance ===self.name ← Rex
pass 1 of 46def __init__(self⟨Dog A⟩, nameRex):7 self.name→ Rex = nameRexAll 4 passes — pass 1 is the card above pass selfnameself.name1 ⟨Dog A⟩ Rex Rex 2 ⟨Cat B⟩ Whiskers Whiskers 3 ⟨Bird C⟩ Tweety Tweety 4 ⟨Bird D⟩ Pingu Pingu dog ← ⟨Dog A⟩
39# Create Dog - uses inherited __init__40dog→ ⟨Dog A⟩ = Dog("Rex")41print(f"Dog name: {dog.nameRex}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog.describe()}")outputDog name: Rexdef speak(self):
pass 1 of 39def speak(self⟨Dog A⟩):10 return f"{self.nameRex} makes a sound"All 3 passes — pass 1 is the card above pass selfself.name1 ⟨Dog A⟩ Rex 2 ⟨Cat B⟩ Whiskers 3 ⟨Bird C⟩ Tweety print(f"Dog speaks: {dog.speak()}")
41print(f"Dog name: {dog.name}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")outputDog speaks: Rex makes a sounddef describe(self):
pass 1 of 212def describe(self⟨Dog A⟩):13 return f"I am {self.nameRex}"print(f"Dog describes: {dog.describe()}")
42print(f"Dog speaks: {dog.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")4445print()4647# Create Cat - also inherits everything48cat = Cat("Whiskers")49print(f"Cat name: {cat.name}")outputDog describes: I am Rexcat ← ⟨Cat B⟩
47# Create Cat - also inherits everything48cat→ ⟨Cat B⟩ = Cat("Whiskers")49print(f"Cat name: {cat.nameWhiskers}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat.describe()}")outputCat name: Whiskersprint(f"Cat speaks: {cat.speak()}")
49print(f"Cat name: {cat.name}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")outputCat speaks: Whiskers makes a sounddef describe(self):
pass 2 of 212def describe(self⟨Cat B⟩):13 return f"I am {self.nameWhiskers}"print(f"Cat describes: {cat.describe()}")
50print(f"Cat speaks: {cat.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")5253print()5455# Create Bird - has additional attribute56bird = Bird("Tweety")57print(f"Bird name: {bird.name}")outputCat describes: I am Whiskersdef __init__(self, name, can_fly=True): # Call parent's __init…
pass 1 of 229class Bird(Animal):30 def __init__(self⟨Bird C⟩, nameTweety, can_flyTrue=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← True
32super().__init__(name)33self.can_fly→ True = can_flyTruebird ← ⟨Bird C⟩
55# Create Bird - has additional attribute56bird→ ⟨Bird C⟩ = Bird("Tweety")57print(f"Bird name: {bird.nameTweety}")58print(f"Bird can fly: {bird.can_flyTrue}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")outputBird name: Tweety Bird can fly: Trueprint(f"Bird speaks: {bird.speak()}")
58print(f"Bird can fly: {bird.can_fly}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")6061print()6263# Bird that can't fly64penguin = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.name}")outputBird speaks: Tweety makes a sounddef __init__(self, name, can_fly=True): # Call parent's __init…
pass 2 of 229class Bird(Animal):30 def __init__(self⟨Bird D⟩, namePingu, can_flyFalse=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← False
32super().__init__(name)33self.can_fly→ False = can_flyFalsepenguin ← ⟨Bird D⟩
63# Bird that can't fly64penguin→ ⟨Bird D⟩ = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.namePingu}")66print(f"Penguin can fly: {penguin.can_flyFalse}")6768print("\n=== Inheritance Rules ===")69print("""701. Child inherits all attributes and methods712. Syntax: class Child(Parent):723. super().__init__() calls parent's __init__734. Child can add new attributes/methods745. 'pass' means no additions (pure inheritance)75""")outputPenguin name: Pingu Penguin can fly: False === Inheritance Rules === 1. Child inherits all attributes and methods 2. Syntax: class Child(Parent): 3. super().__init__() calls parent's __init__ 4. Child can add new attributes/methods 5. 'pass' means no additions (pure inheritance)
"""Base class for all animals."""
3class Animal:4 """Base class for all animals."""5 6 def __init__(self, name):7 self.name = name8 9 def speak(self):10 return f"{self.name} makes a sound"11 12 def describe(self):13 return f"I am {self.name}"141516# Dog inherits from Animal17class Dog(Animal):18 """Dog class inherits from Animal."""19 pass # No additional code - inherits everything202122# Cat inherits from Animal23class Cat(Animal):24 """Cat class inherits from Animal."""25 pass262728# Bird with additional attribute29class Bird(Animal):30 def __init__(self, name, can_fly=True):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_fly343536# Demonstrate basic inheritance37print("=== Basic Inheritance ===\n")3839# Create Dog - uses inherited __init__40dog = Dog("Luna")41print(f"Dog name: {dog.name}")output=== Basic Inheritance ===self.name ← Luna
pass 1 of 46def __init__(self⟨Dog A⟩, nameLuna):7 self.name→ Luna = nameLunaAll 4 passes — pass 1 is the card above pass selfnameself.name1 ⟨Dog A⟩ Luna Luna 2 ⟨Cat B⟩ Whiskers Whiskers 3 ⟨Bird C⟩ Tweety Tweety 4 ⟨Bird D⟩ Pingu Pingu dog ← ⟨Dog A⟩
39# Create Dog - uses inherited __init__40dog→ ⟨Dog A⟩ = Dog("Luna")41print(f"Dog name: {dog.nameLuna}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog.describe()}")outputDog name: Lunadef speak(self):
pass 1 of 39def speak(self⟨Dog A⟩):10 return f"{self.nameLuna} makes a sound"All 3 passes — pass 1 is the card above pass selfself.name1 ⟨Dog A⟩ Luna 2 ⟨Cat B⟩ Whiskers 3 ⟨Bird C⟩ Tweety print(f"Dog speaks: {dog.speak()}")
41print(f"Dog name: {dog.name}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")outputDog speaks: Luna makes a sounddef describe(self):
pass 1 of 212def describe(self⟨Dog A⟩):13 return f"I am {self.nameLuna}"print(f"Dog describes: {dog.describe()}")
42print(f"Dog speaks: {dog.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")4445print()4647# Create Cat - also inherits everything48cat = Cat("Whiskers")49print(f"Cat name: {cat.name}")outputDog describes: I am Lunacat ← ⟨Cat B⟩
47# Create Cat - also inherits everything48cat→ ⟨Cat B⟩ = Cat("Whiskers")49print(f"Cat name: {cat.nameWhiskers}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat.describe()}")outputCat name: Whiskersprint(f"Cat speaks: {cat.speak()}")
49print(f"Cat name: {cat.name}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")outputCat speaks: Whiskers makes a sounddef describe(self):
pass 2 of 212def describe(self⟨Cat B⟩):13 return f"I am {self.nameWhiskers}"print(f"Cat describes: {cat.describe()}")
50print(f"Cat speaks: {cat.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")5253print()5455# Create Bird - has additional attribute56bird = Bird("Tweety")57print(f"Bird name: {bird.name}")outputCat describes: I am Whiskersdef __init__(self, name, can_fly=True): # Call parent's __init…
pass 1 of 229class Bird(Animal):30 def __init__(self⟨Bird C⟩, nameTweety, can_flyTrue=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← True
32super().__init__(name)33self.can_fly→ True = can_flyTruebird ← ⟨Bird C⟩
55# Create Bird - has additional attribute56bird→ ⟨Bird C⟩ = Bird("Tweety")57print(f"Bird name: {bird.nameTweety}")58print(f"Bird can fly: {bird.can_flyTrue}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")outputBird name: Tweety Bird can fly: Trueprint(f"Bird speaks: {bird.speak()}")
58print(f"Bird can fly: {bird.can_fly}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")6061print()6263# Bird that can't fly64penguin = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.name}")outputBird speaks: Tweety makes a sounddef __init__(self, name, can_fly=True): # Call parent's __init…
pass 2 of 229class Bird(Animal):30 def __init__(self⟨Bird D⟩, namePingu, can_flyFalse=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← False
32super().__init__(name)33self.can_fly→ False = can_flyFalsepenguin ← ⟨Bird D⟩
63# Bird that can't fly64penguin→ ⟨Bird D⟩ = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.namePingu}")66print(f"Penguin can fly: {penguin.can_flyFalse}")6768print("\n=== Inheritance Rules ===")69print("""701. Child inherits all attributes and methods712. Syntax: class Child(Parent):723. super().__init__() calls parent's __init__734. Child can add new attributes/methods745. 'pass' means no additions (pure inheritance)75""")outputPenguin name: Pingu Penguin can fly: False === Inheritance Rules === 1. Child inherits all attributes and methods 2. Syntax: class Child(Parent): 3. super().__init__() calls parent's __init__ 4. Child can add new attributes/methods 5. 'pass' means no additions (pure inheritance)
"""Base class for all animals."""
3class Animal:4 """Base class for all animals."""5 6 def __init__(self, name):7 self.name = name8 9 def speak(self):10 return f"{self.name} makes a sound"11 12 def describe(self):13 return f"I am {self.name}"141516# Dog inherits from Animal17class Dog(Animal):18 """Dog class inherits from Animal."""19 pass # No additional code - inherits everything202122# Cat inherits from Animal23class Cat(Animal):24 """Cat class inherits from Animal."""25 pass262728# Bird with additional attribute29class Bird(Animal):30 def __init__(self, name, can_fly=True):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_fly343536# Demonstrate basic inheritance37print("=== Basic Inheritance ===\n")3839# Create Dog - uses inherited __init__40dog = Dog("Buddy")41print(f"Dog name: {dog.name}")output=== Basic Inheritance ===self.name ← Buddy
pass 1 of 46def __init__(self⟨Dog A⟩, nameBuddy):7 self.name→ Buddy = nameBuddyAll 4 passes — pass 1 is the card above pass selfnameself.name1 ⟨Dog A⟩ Buddy Buddy 2 ⟨Cat B⟩ Whiskers Whiskers 3 ⟨Bird C⟩ Robin Robin 4 ⟨Bird D⟩ Pingu Pingu dog ← ⟨Dog A⟩
39# Create Dog - uses inherited __init__40dog→ ⟨Dog A⟩ = Dog("Buddy")41print(f"Dog name: {dog.nameBuddy}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog.describe()}")outputDog name: Buddydef speak(self):
pass 1 of 39def speak(self⟨Dog A⟩):10 return f"{self.nameBuddy} makes a sound"All 3 passes — pass 1 is the card above pass selfself.name1 ⟨Dog A⟩ Buddy 2 ⟨Cat B⟩ Whiskers 3 ⟨Bird C⟩ Robin print(f"Dog speaks: {dog.speak()}")
41print(f"Dog name: {dog.name}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")outputDog speaks: Buddy makes a sounddef describe(self):
pass 1 of 212def describe(self⟨Dog A⟩):13 return f"I am {self.nameBuddy}"print(f"Dog describes: {dog.describe()}")
42print(f"Dog speaks: {dog.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")4445print()4647# Create Cat - also inherits everything48cat = Cat("Whiskers")49print(f"Cat name: {cat.name}")outputDog describes: I am Buddycat ← ⟨Cat B⟩
47# Create Cat - also inherits everything48cat→ ⟨Cat B⟩ = Cat("Whiskers")49print(f"Cat name: {cat.nameWhiskers}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat.describe()}")outputCat name: Whiskersprint(f"Cat speaks: {cat.speak()}")
49print(f"Cat name: {cat.name}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")outputCat speaks: Whiskers makes a sounddef describe(self):
pass 2 of 212def describe(self⟨Cat B⟩):13 return f"I am {self.nameWhiskers}"print(f"Cat describes: {cat.describe()}")
50print(f"Cat speaks: {cat.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")5253print()5455# Create Bird - has additional attribute56bird = Bird("Robin")57print(f"Bird name: {bird.name}")outputCat describes: I am Whiskersdef __init__(self, name, can_fly=True): # Call parent's __init…
pass 1 of 229class Bird(Animal):30 def __init__(self⟨Bird C⟩, nameRobin, can_flyTrue=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← True
32super().__init__(name)33self.can_fly→ True = can_flyTruebird ← ⟨Bird C⟩
55# Create Bird - has additional attribute56bird→ ⟨Bird C⟩ = Bird("Robin")57print(f"Bird name: {bird.nameRobin}")58print(f"Bird can fly: {bird.can_flyTrue}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")outputBird name: Robin Bird can fly: Trueprint(f"Bird speaks: {bird.speak()}")
58print(f"Bird can fly: {bird.can_fly}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")6061print()6263# Bird that can't fly64penguin = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.name}")outputBird speaks: Robin makes a sounddef __init__(self, name, can_fly=True): # Call parent's __init…
pass 2 of 229class Bird(Animal):30 def __init__(self⟨Bird D⟩, namePingu, can_flyFalse=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← False
32super().__init__(name)33self.can_fly→ False = can_flyFalsepenguin ← ⟨Bird D⟩
63# Bird that can't fly64penguin→ ⟨Bird D⟩ = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.namePingu}")66print(f"Penguin can fly: {penguin.can_flyFalse}")6768print("\n=== Inheritance Rules ===")69print("""701. Child inherits all attributes and methods712. Syntax: class Child(Parent):723. super().__init__() calls parent's __init__734. Child can add new attributes/methods745. 'pass' means no additions (pure inheritance)75""")outputPenguin name: Pingu Penguin can fly: False === Inheritance Rules === 1. Child inherits all attributes and methods 2. Syntax: class Child(Parent): 3. super().__init__() calls parent's __init__ 4. Child can add new attributes/methods 5. 'pass' means no additions (pure inheritance)
"""Base class for all animals."""
3class Animal:4 """Base class for all animals."""5 6 def __init__(self, name):7 self.name = name8 9 def speak(self):10 return f"{self.name} makes a sound"11 12 def describe(self):13 return f"I am {self.name}"141516# Dog inherits from Animal17class Dog(Animal):18 """Dog class inherits from Animal."""19 pass # No additional code - inherits everything202122# Cat inherits from Animal23class Cat(Animal):24 """Cat class inherits from Animal."""25 pass262728# Bird with additional attribute29class Bird(Animal):30 def __init__(self, name, can_fly=True):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_fly343536# Demonstrate basic inheritance37print("=== Basic Inheritance ===\n")3839# Create Dog - uses inherited __init__40dog = Dog("Buddy")41print(f"Dog name: {dog.name}")output=== Basic Inheritance ===self.name ← Buddy
pass 1 of 46def __init__(self⟨Dog A⟩, nameBuddy):7 self.name→ Buddy = nameBuddyAll 4 passes — pass 1 is the card above pass selfnameself.name1 ⟨Dog A⟩ Buddy Buddy 2 ⟨Cat B⟩ Whiskers Whiskers 3 ⟨Bird C⟩ Kiwi Kiwi 4 ⟨Bird D⟩ Pingu Pingu dog ← ⟨Dog A⟩
39# Create Dog - uses inherited __init__40dog→ ⟨Dog A⟩ = Dog("Buddy")41print(f"Dog name: {dog.nameBuddy}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog.describe()}")outputDog name: Buddydef speak(self):
pass 1 of 39def speak(self⟨Dog A⟩):10 return f"{self.nameBuddy} makes a sound"All 3 passes — pass 1 is the card above pass selfself.name1 ⟨Dog A⟩ Buddy 2 ⟨Cat B⟩ Whiskers 3 ⟨Bird C⟩ Kiwi print(f"Dog speaks: {dog.speak()}")
41print(f"Dog name: {dog.name}")42print(f"Dog speaks: {dog⟨Dog A⟩.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")outputDog speaks: Buddy makes a sounddef describe(self):
pass 1 of 212def describe(self⟨Dog A⟩):13 return f"I am {self.nameBuddy}"print(f"Dog describes: {dog.describe()}")
42print(f"Dog speaks: {dog.speak()}")43print(f"Dog describes: {dog⟨Dog A⟩.describe()}")4445print()4647# Create Cat - also inherits everything48cat = Cat("Whiskers")49print(f"Cat name: {cat.name}")outputDog describes: I am Buddycat ← ⟨Cat B⟩
47# Create Cat - also inherits everything48cat→ ⟨Cat B⟩ = Cat("Whiskers")49print(f"Cat name: {cat.nameWhiskers}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat.describe()}")outputCat name: Whiskersprint(f"Cat speaks: {cat.speak()}")
49print(f"Cat name: {cat.name}")50print(f"Cat speaks: {cat⟨Cat B⟩.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")outputCat speaks: Whiskers makes a sounddef describe(self):
pass 2 of 212def describe(self⟨Cat B⟩):13 return f"I am {self.nameWhiskers}"print(f"Cat describes: {cat.describe()}")
50print(f"Cat speaks: {cat.speak()}")51print(f"Cat describes: {cat⟨Cat B⟩.describe()}")5253print()5455# Create Bird - has additional attribute56bird = Bird("Kiwi", can_fly=False)57print(f"Bird name: {bird.name}")outputCat describes: I am Whiskersdef __init__(self, name, can_fly=True): # Call parent's __init…
pass 1 of 229class Bird(Animal):30 def __init__(self⟨Bird C⟩, nameKiwi, can_flyFalse=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← False
32super().__init__(name)33self.can_fly→ False = can_flyFalsebird ← ⟨Bird C⟩
55# Create Bird - has additional attribute56bird→ ⟨Bird C⟩ = Bird("Kiwi", can_fly=False)57print(f"Bird name: {bird.nameKiwi}")58print(f"Bird can fly: {bird.can_flyFalse}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")outputBird name: Kiwi Bird can fly: Falseprint(f"Bird speaks: {bird.speak()}")
58print(f"Bird can fly: {bird.can_fly}")59print(f"Bird speaks: {bird⟨Bird C⟩.speak()}")6061print()6263# Bird that can't fly64penguin = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.name}")outputBird speaks: Kiwi makes a sounddef __init__(self, name, can_fly=True): # Call parent's __init…
pass 2 of 229class Bird(Animal):30 def __init__(self⟨Bird D⟩, namePingu, can_flyFalse=TrueTrue):31 # Call parent's __init__32 super().__init__(name)33 self.can_fly = can_flyself.can_fly ← False
32super().__init__(name)33self.can_fly→ False = can_flyFalsepenguin ← ⟨Bird D⟩
63# Bird that can't fly64penguin→ ⟨Bird D⟩ = Bird("Pingu", can_fly=False)65print(f"Penguin name: {penguin.namePingu}")66print(f"Penguin can fly: {penguin.can_flyFalse}")6768print("\n=== Inheritance Rules ===")69print("""701. Child inherits all attributes and methods712. Syntax: class Child(Parent):723. super().__init__() calls parent's __init__734. Child can add new attributes/methods745. 'pass' means no additions (pure inheritance)75""")outputPenguin name: Pingu Penguin can fly: False === Inheritance Rules === 1. Child inherits all attributes and methods 2. Syntax: class Child(Parent): 3. super().__init__() calls parent's __init__ 4. Child can add new attributes/methods 5. 'pass' means no additions (pure inheritance)
class Child(Parent): inherits all of Parent's methods and attributes.
Call parent constructor
Initialize parent attributes with super().
# Using super() to Call Parent's __init__
class Person:
"""Base class for people."""
def __init__(self, name, age):
self.name = name
self.age = age
print(f" Person.__init__ called: {name}, {age}")
def introduce(self):
return f"I'm {self.name}, {self.age} years old"
class Student(Person):
"""Student inherits from Person."""
def __init__(self, name, age, student_id):
print(f" Student.__init__ starting...")
super().__init__(name, age)
self.student_id = student_id
print(f" Student.__init__ completed: id={student_id}")
def introduce(self):
return f"I'm {self.name}, student #{self.student_id}"
class Employee(Person):
"""Employee inherits from Person."""
def __init__(self, name, age, department, salary):
super().__init__(name, age)
self.department = department
self.salary = salary
def introduce(self):
return f"I'm {self.name} from {self.department}"
class Manager(Employee):
"""Manager inherits from Employee (which inherits from Person)."""
def __init__(self, name, age, department, salary, team_size):
# super() calls Employee.__init__
super().__init__(name, age, department, salary)
self.team_size = team_size
def introduce(self):
return f"I'm {self.name}, managing {self.team_size} people in {self.department}"
print("=== Understanding super().__init__() ===\n")
# Simple case: Student
print("Creating Student:")
student = Student("Alice", 20, "S12345")
print(f"Result: {student.introduce()}")
print(f"Has name: {student.name}")
print(f"Has age: {student.age}")
print(f"Has student_id: {student.student_id}")
print("\n" + "="*40 + "\n")
# Employee case
print("Creating Employee:")
emp = Employee("Bob", 35, "Engineering", 75000)
print(f"Result: {emp.introduce()}")
print(f"Has name: {emp.name}")
print(f"Has age: {emp.age}")
print(f"Has department: {emp.department}")
print(f"Has salary: {emp.salary}")
print("\n" + "="*40 + "\n")
# Inheritance chain: Manager -> Employee -> Person
print("Creating Manager (three-level inheritance):")
manager = Manager("Carol", 45, "Engineering", 120000, 8)
print(f"Result: {manager.introduce()}")
print(f"Has name: {manager.name} (from Person)")
print(f"Has age: {manager.age} (from Person)")
print(f"Has department: {manager.department} (from Employee)")
print(f"Has salary: {manager.salary} (from Employee)")
print(f"Has team_size: {manager.team_size} (from Manager)")
print("\n=== super() Key Points ===")
print("""
1. super() returns a proxy to the parent class
2. super().__init__() calls parent's constructor
3. Must pass required arguments to parent
4. Each level in chain calls its parent
5. Attributes accumulate through the chain:
Manager has: name, age (Person)
+ department, salary (Employee)
+ team_size (Manager)
""")
"""Base class for people."""
3class Person: #?personclass4 """Base class for people."""5 6 def __init__(self, name, age): #?personinitf7 self.name = name #?nameattr8 self.age = age #?ageattr9 print(f" Person.__init__ called: {name}, {age}")10 11 def introduce(self): #?introduce12 return f"I'm {self.name}, {self.age} years old"131415class Student(Person): #?studentclass16 """Student inherits from Person."""17 18 def __init__(self, name, age, student_id): #?studentinitf19 print(f" Student.__init__ starting...")20 super().__init__(name, age) #?superinit21 self.student_id = student_id #?studentidattr22 print(f" Student.__init__ completed: id={student_id}")23 24 def introduce(self): #?studentintroduce25 return f"I'm {self.name}, student #{self.student_id}"262728class Employee(Person): #?employeeclass29 """Employee inherits from Person."""30 31 def __init__(self, name, age, department, salary): #?employeeinit32 super().__init__(name, age) #?employeesuper33 self.department = department #?deptattr34 self.salary = salary #?salaryattr35 36 def introduce(self):37 return f"I'm {self.name} from {self.department}"383940class Manager(Employee): #?managerclass41 """Manager inherits from Employee (which inherits from Person)."""42 43 def __init__(self, name, age, department, salary, team_size): #?managerinit44 # super() calls Employee.__init__ #?managersuper45 super().__init__(name, age, department, salary) #?superchain46 self.team_size = team_size #?teamsizeattr47 48 def introduce(self):49 return f"I'm {self.name}, managing {self.team_size} people in {self.department}"505152print("=== Understanding super().__init__() ===\n")5354# Simple case: Student #?studentdemo55print("Creating Student:")56student = Student("Alice", 20, "S12345") #?studentinstance57print(f"Result: {student.introduce()}")output=== Understanding super().__init__() === Creating Student:def __init__(self, name, age, student_id): #?studentinitf
18def __init__(self⟨Student A⟩, nameAlice, age20, student_idS12345): #?studentinitf19 print(f" Student.__init__ starting...")20 super().__init__(name, age) #?superinitoutput Student.__init__ starting...self.name ← Alice, self.age ← 20
pass 1 of 36def __init__(self⟨Student A⟩, nameAlice, age20): #?personinitf7 self.name→ Alice = nameAlice #?nameattr8 self.age→ 20 = age20 #?ageattr9 print(f" Person.__init__ called: {nameAlice}, {age20}")output Person.__init__ called: Alice, 20All 3 passes — pass 1 is the card above pass selfnameageself.nameself.age1 ⟨Student A⟩ Alice 20 Alice 20 2 ⟨Employee B⟩ Bob 35 Bob 35 3 ⟨Manager C⟩ Carol 45 Carol 45 self.student_id ← S12345
20super().__init__(name, age) #?superinit21self.student_id→ S12345 = student_idS12345 #?studentidattr22print(f" Student.__init__ completed: id={student_idS12345}")output Student.__init__ completed: id=S12345student ← ⟨Student A⟩
55print("Creating Student:")56student→ ⟨Student A⟩ = Student("Alice", 20, "S12345") #?studentinstance57print(f"Result: {student⟨Student A⟩.introduce()}")58print(f"Has name: {student.name}")def introduce(self): #?studentintroduce
24def introduce(self⟨Student A⟩): #?studentintroduce25 return f"I'm {self.nameAlice}, student #{self.student_idS12345}"print(f"Result: {student.introduce()}")
56student = Student("Alice", 20, "S12345") #?studentinstance57print(f"Result: {student⟨Student A⟩.introduce()}")58print(f"Has name: {student.nameAlice}")59print(f"Has age: {student.age20}")60print(f"Has student_id: {student.student_idS12345}")6162print("\n" + "="*40 + "\n")6364# Employee case #?employeedemo65print("Creating Employee:")66emp = Employee("Bob", 35, "Engineering", 75000)67print(f"Result: {emp.introduce()}")outputResult: I'm Alice, student #S12345 Has name: Alice Has age: 20 Has student_id: S12345 ======================================== Creating Employee:def __init__(self, name, age, department, salary): #?employeeinit
pass 1 of 231def __init__(self⟨Employee B⟩, nameBob, age35, departmentEngineering, salary75000): #?employeeinit32 super().__init__(name, age) #?employeesuper33 self.department = department #?deptattrself.department ← Engineering, self.salary ← 75000
32super().__init__(name, age) #?employeesuper33self.department→ Engineering = departmentEngineering #?deptattr34self.salary→ 75000 = salary75000 #?salaryattremp ← ⟨Employee B⟩
65print("Creating Employee:")66emp→ ⟨Employee B⟩ = Employee("Bob", 35, "Engineering", 75000)67print(f"Result: {emp⟨Employee B⟩.introduce()}")68print(f"Has name: {emp.name}")def introduce(self):
36def introduce(self⟨Employee B⟩):37 return f"I'm {self.nameBob} from {self.departmentEngineering}"print(f"Result: {emp.introduce()}")
66emp = Employee("Bob", 35, "Engineering", 75000)67print(f"Result: {emp⟨Employee B⟩.introduce()}")68print(f"Has name: {emp.nameBob}")69print(f"Has age: {emp.age35}")70print(f"Has department: {emp.departmentEngineering}")71print(f"Has salary: {emp.salary75000}")7273print("\n" + "="*40 + "\n")7475# Inheritance chain: Manager -> Employee -> Person #?managerdemo76print("Creating Manager (three-level inheritance):")77manager = Manager("Carol", 45, "Engineering", 120000, 8) #?managerinstance78print(f"Result: {manager.introduce()}")outputResult: I'm Bob from Engineering Has name: Bob Has age: 35 Has department: Engineering Has salary: 75000 ======================================== Creating Manager (three-level inheritance):def __init__(self, name, age, department, salary, team_size): #?manage…
43def __init__(self⟨Manager C⟩, nameCarol, age45, departmentEngineering, salary120000, team_size8): #?managerinit44 # super() calls Employee.__init__ #?managersuper45 super().__init__(name, age, department, salary) #?superchain46 self.team_size = team_size #?teamsizeattrdef __init__(self, name, age, department, salary): #?employeeinit
pass 2 of 231def __init__(self⟨Manager C⟩, nameCarol, age45, departmentEngineering, salary120000): #?employeeinit32 super().__init__(name, age) #?employeesuper33 self.department = department #?deptattrself.department ← Engineering, self.salary ← 120000
32super().__init__(name, age) #?employeesuper33self.department→ Engineering = departmentEngineering #?deptattr34self.salary→ 120000 = salary120000 #?salaryattrself.team_size ← 8
45super().__init__(name, age, department, salary) #?superchain46self.team_size→ 8 = team_size8 #?teamsizeattrmanager ← ⟨Manager C⟩
76print("Creating Manager (three-level inheritance):")77manager→ ⟨Manager C⟩ = Manager("Carol", 45, "Engineering", 120000, 8) #?managerinstance78print(f"Result: {manager⟨Manager C⟩.introduce()}")79print(f"Has name: {manager.name} (from Person)")def introduce(self):
48def introduce(self⟨Manager C⟩):49 return f"I'm {self.nameCarol}, managing {self.team_size8} people in {self.departmentEngineering}"print(f"Result: {manager.introduce()}")
77manager = Manager("Carol", 45, "Engineering", 120000, 8) #?managerinstance78print(f"Result: {manager⟨Manager C⟩.introduce()}")79print(f"Has name: {manager.nameCarol} (from Person)")80print(f"Has age: {manager.age45} (from Person)")81print(f"Has department: {manager.departmentEngineering} (from Employee)")82print(f"Has salary: {manager.salary120000} (from Employee)")83print(f"Has team_size: {manager.team_size8} (from Manager)")8485print("\n=== super() Key Points ===")86print("""871. super() returns a proxy to the parent class882. super().__init__() calls parent's constructor893. Must pass required arguments to parent904. Each level in chain calls its parent915. Attributes accumulate through the chain:92 Manager has: name, age (Person)93 + department, salary (Employee)94 + team_size (Manager)95""")outputResult: I'm Carol, managing 8 people in Engineering Has name: Carol (from Person) Has age: 45 (from Person) Has department: Engineering (from Employee) Has salary: 120000 (from Employee) Has team_size: 8 (from Manager) === super() Key Points === 1. super() returns a proxy to the parent class 2. super().__init__() calls parent's constructor 3. Must pass required arguments to parent 4. Each level in chain calls its parent 5. Attributes accumulate through the chain: Manager has: name, age (Person) + department, salary (Employee) + team_size (Manager)
super().__init__(args) calls parent's __init__. Always call it first.
Override methods
Replace parent behavior with child-specific implementation.
# Method Overriding
class Shape:
"""Base class for geometric shapes."""
def __init__(self, name):
self.name = name
def area(self):
return 0 # Default: no area
def perimeter(self):
return 0 # Default: no perimeter
def describe(self):
return f"I am a {self.name}"
class Rectangle(Shape):
"""Rectangle overrides area and perimeter."""
def __init__(self, width, height):
super().__init__("Rectangle")
self.width = width
self.height = height
# Override area method
def area(self):
return self.width * self.height
# Override perimeter method
def perimeter(self):
return 2 * (self.width + self.height)
# Override describe
def describe(self):
return f"Rectangle: {self.width} x {self.height}"
class Circle(Shape):
"""Circle overrides area and perimeter."""
PI = 3.14159
def __init__(self, radius):
super().__init__("Circle")
self.radius = radius
def area(self):
return Circle.PI * self.radius ** 2
def perimeter(self):
return 2 * Circle.PI * self.radius
def describe(self):
return f"Circle: radius = {self.radius}"
class Triangle(Shape):
"""Triangle overrides methods."""
def __init__(self, a, b, c):
super().__init__("Triangle")
self.a = a # Side lengths
self.b = b
self.c = c
def area(self):
# Heron's formula
s = (self.a + self.b + self.c) / 2
return (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5
def perimeter(self):
return self.a + self.b + self.c
def describe(self):
return f"Triangle: sides {self.a}, {self.b}, {self.c}"
# Demonstration
print("=== Method Overriding ===\n")
# Create shapes
shapes = [
Rectangle(5, 3),
Circle(4),
Triangle(3, 4, 5),
]
# Polymorphic behavior - same method, different results
for shape in shapes:
print(shape.describe())
print(f" Area: {shape.area():.2f}")
print(f" Perimeter: {shape.perimeter():.2f}")
print()
# The base Shape class
print("Base Shape class (no override):")
generic = Shape("Unknown")
print(f" {generic.describe()}")
print(f" Area: {generic.area()}")
print(f" Perimeter: {generic.perimeter()}")
print("\n=== Override Rules ===")
print("""
1. Same method name as parent
2. Same parameters (usually)
3. Different implementation
4. Child's version is called on child objects
5. Parent's version still exists in parent objects
6. No special keyword needed (unlike Java's @Override)
""")
PI ← (empty)
3class Shape: #?shapeclass4 """Base class for geometric shapes."""5 6 def __init__(self, name): #?shapeinit7 self.name = name8 9 def area(self): #?shapearea10 return 0 # Default: no area11 12 def perimeter(self): #?shapeperimeter13 return 0 # Default: no perimeter14 15 def describe(self): #?shapedescribe16 return f"I am a {self.name}"171819class Rectangle(Shape): #?rectangleclass20 """Rectangle overrides area and perimeter."""21 22 def __init__(self, width, height): #?rectinit23 super().__init__("Rectangle") #?rectsuper24 self.width = width25 self.height = height26 27 # Override area method #?overridearea28 def area(self): #?rectarea29 return self.width * self.height30 31 # Override perimeter method #?overrideperimeter32 def perimeter(self): #?rectperimeter33 return 2 * (self.width + self.height)34 35 # Override describe #?overridedescribe36 def describe(self): #?rectdescribe37 return f"Rectangle: {self.width} x {self.height}"383940class Circle(Shape): #?circleclass41 """Circle overrides area and perimeter."""42 43 PI→ (empty) = 3.14159 #?piconstant44 45 def __init__(self, radius):46 super().__init__("Circle")47 self.radius = radius48 49 def area(self): #?circlearea50 return Circle.PI * self.radius ** 251 52 def perimeter(self): #?circleperimeter53 return 2 * Circle.PI * self.radius54 55 def describe(self):56 return f"Circle: radius = {self.radius}"575859class Triangle(Shape): #?triangleclass60 """Triangle overrides methods."""61 62 def __init__(self, a, b, c): #?triangleinit63 super().__init__("Triangle")64 self.a = a # Side lengths65 self.b = b66 self.c = c67 68 def area(self): #?trianglearea69 # Heron's formula70 s = (self.a + self.b + self.c) / 2 #?herons71 return (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.572 73 def perimeter(self):74 return self.a + self.b + self.c75 76 def describe(self):77 return f"Triangle: sides {self.a}, {self.b}, {self.c}"787980# Demonstration81print("=== Method Overriding ===\n")8283# Create shapes #?createshapes84shapes = [ #?shapelist85 Rectangle(5, 3),86 Circle(4),87 Triangle(3, 4, 5),88]output=== Method Overriding ===def __init__(self, width, height): #?rectinit
22def __init__(self⟨Rectangle A⟩, width5, height3): #?rectinit23 super().__init__("Rectangle") #?rectsuper24 self.width = widthself.name ← Rectangle
pass 1 of 46def __init__(self⟨Rectangle A⟩, nameRectangle): #?shapeinit7 self.name→ Rectangle = nameRectangleAll 4 passes — pass 1 is the card above pass selfnameself.name1 ⟨Rectangle A⟩ Rectangle Rectangle 2 ⟨Circle B⟩ Circle Circle 3 ⟨Triangle C⟩ Triangle Triangle 4 ⟨Shape D⟩ Unknown Unknown self.width ← 5, self.height ← 3
23super().__init__("Rectangle") #?rectsuper24self.width→ 5 = width525self.height→ 3 = height3def __init__(self, radius):
45def __init__(self⟨Circle B⟩, radius4):46 super().__init__("Circle")47 self.radius = radiusself.radius ← 4
46super().__init__("Circle")47self.radius→ 4 = radius4def __init__(self, a, b, c): #?triangleinit
62def __init__(self⟨Triangle C⟩, a3, b4, c5): #?triangleinit63 super().__init__("Triangle")64 self.a = a # Side lengthsself.a ← 3, self.b ← 4, self.c ← 5
63super().__init__("Triangle")64self.a→ 3 = a3 # Side lengths65self.b→ 4 = b466self.c→ 5 = c5shapes ← [⟨Rectangle A⟩, ⟨Circle B⟩, ⟨Triangle C⟩]
83# Create shapes #?createshapes84shapes→ [⟨Rectangle A⟩, ⟨Circle B⟩, ⟨Triangle C⟩] = [ #?shapelist85 Rectangle(5, 3),86 Circle(4),87 Triangle(3, 4, 5),88]for shape in shapes: #?iterateshapes
pass 1 of 390# Polymorphic behavior - same method, different results #?polymorphism91for shape⟨Rectangle A⟩ in shapes[⟨Rectangle A⟩, ⟨Circle B⟩, ⟨Triangle C⟩]: #?iterateshapes92 print(shape⟨Rectangle A⟩.describe()) #?calldescribe93 print(f" Area: {shape.area():.2f}") #?callareaAll 3 passes — pass 1 is the card above pass shapeselfself.widthself.heightself.radiusself.aself.bself.c1 ⟨Rectangle A⟩ ⟨Rectangle A⟩ 5 3 — — — — 2 ⟨Circle B⟩ ⟨Circle B⟩ — — 4 — — — 3 ⟨Triangle C⟩ ⟨Triangle C⟩ — — — 3 4 5 def describe(self): #?rectdescribe
35# Override describe #?overridedescribe36def describe(self⟨Rectangle A⟩): #?rectdescribe37 return f"Rectangle: {self.width5} x {self.height3}"print(shape.describe()) #?calldescribe
91for shape in shapes: #?iterateshapes92 print(shape⟨Rectangle A⟩.describe()) #?calldescribe93 print(f" Area: {shape⟨Rectangle A⟩.area():.2f}") #?callarea94 print(f" Perimeter: {shape.perimeter():.2f}") #?callperimeteroutputRectangle: 5 x 3def area(self): #?rectarea
27# Override area method #?overridearea28def area(self⟨Rectangle A⟩): #?rectarea29 return self.width5 * self.height3print(f" Area: {shape.area():.2f}") #?callarea
92print(shape.describe()) #?calldescribe93print(f" Area: {shape⟨Rectangle A⟩.area():.2f}") #?callarea94print(f" Perimeter: {shape⟨Rectangle A⟩.perimeter():.2f}") #?callperimeter95print()output Area: 15.00def perimeter(self): #?rectperimeter
31# Override perimeter method #?overrideperimeter32def perimeter(self⟨Rectangle A⟩): #?rectperimeter33 return 2 * (self.width5 + self.height3)print(f" Perimeter: {shape.perimeter():.2f}") #?callperimeter
93print(f" Area: {shape.area():.2f}") #?callarea94print(f" Perimeter: {shape⟨Rectangle A⟩.perimeter():.2f}") #?callperimeter95print()output Perimeter: 16.00def describe(self):
55def describe(self⟨Circle B⟩):56 return f"Circle: radius = {self.radius4}"print(shape.describe()) #?calldescribe
91for shape in shapes: #?iterateshapes92 print(shape⟨Circle B⟩.describe()) #?calldescribe93 print(f" Area: {shape⟨Circle B⟩.area():.2f}") #?callarea94 print(f" Perimeter: {shape.perimeter():.2f}") #?callperimeteroutputCircle: radius = 4def area(self): #?circlearea
49def area(self⟨Circle B⟩): #?circlearea50 return Circle.PI3.14159 * self.radius4 ** 2print(f" Area: {shape.area():.2f}") #?callarea
92print(shape.describe()) #?calldescribe93print(f" Area: {shape⟨Circle B⟩.area():.2f}") #?callarea94print(f" Perimeter: {shape⟨Circle B⟩.perimeter():.2f}") #?callperimeter95print()output Area: 50.27def perimeter(self): #?circleperimeter
52def perimeter(self⟨Circle B⟩): #?circleperimeter53 return 2 * Circle.PI3.14159 * self.radius4print(f" Perimeter: {shape.perimeter():.2f}") #?callperimeter
93print(f" Area: {shape.area():.2f}") #?callarea94print(f" Perimeter: {shape⟨Circle B⟩.perimeter():.2f}") #?callperimeter95print()output Perimeter: 25.13def describe(self):
76def describe(self⟨Triangle C⟩):77 return f"Triangle: sides {self.a3}, {self.b4}, {self.c5}"print(shape.describe()) #?calldescribe
91for shape in shapes: #?iterateshapes92 print(shape⟨Triangle C⟩.describe()) #?calldescribe93 print(f" Area: {shape⟨Triangle C⟩.area():.2f}") #?callarea94 print(f" Perimeter: {shape.perimeter():.2f}") #?callperimeteroutputTriangle: sides 3, 4, 5s ← 6.0
68def area(self⟨Triangle C⟩): #?trianglearea69 # Heron's formula70 s→ 6.0 = (self.a3 + self.b4 + self.c5) / 2 #?herons71 return (s6.0 * (s - self.a3) * (s - self.b4) * (s - self.c5)) ** 0.5print(f" Area: {shape.area():.2f}") #?callarea
92print(shape.describe()) #?calldescribe93print(f" Area: {shape⟨Triangle C⟩.area():.2f}") #?callarea94print(f" Perimeter: {shape⟨Triangle C⟩.perimeter():.2f}") #?callperimeter95print()output Area: 6.00def perimeter(self):
73def perimeter(self⟨Triangle C⟩):74 return self.a3 + self.b4 + self.c5print(f" Perimeter: {shape.perimeter():.2f}") #?callperimeter
93print(f" Area: {shape.area():.2f}") #?callarea94print(f" Perimeter: {shape⟨Triangle C⟩.perimeter():.2f}") #?callperimeter95print()output Perimeter: 12.00print("Base Shape class (no override):")
97# The base Shape class #?baseshape98print("Base Shape class (no override):")99generic = Shape("Unknown") #?genericshape100print(f" {generic.describe()}")outputBase Shape class (no override):generic ← ⟨Shape D⟩
98print("Base Shape class (no override):")99generic→ ⟨Shape D⟩ = Shape("Unknown") #?genericshape100print(f" {generic⟨Shape D⟩.describe()}")101print(f" Area: {generic.area()}")def describe(self): #?shapedescribe
15def describe(self⟨Shape D⟩): #?shapedescribe16 return f"I am a {self.nameUnknown}"print(f" {generic.describe()}")
99generic = Shape("Unknown") #?genericshape100print(f" {generic⟨Shape D⟩.describe()}")101print(f" Area: {generic⟨Shape D⟩.area()}")102print(f" Perimeter: {generic.perimeter()}")output I am a Unknowndef area(self): #?shapearea
9def area(self⟨Shape D⟩): #?shapearea10 return 0 # Default: no areaprint(f" Area: {generic.area()}")
100print(f" {generic.describe()}")101print(f" Area: {generic⟨Shape D⟩.area()}")102print(f" Perimeter: {generic⟨Shape D⟩.perimeter()}")output Area: 0def perimeter(self): #?shapeperimeter
12def perimeter(self⟨Shape D⟩): #?shapeperimeter13 return 0 # Default: no perimeterprint(f" Perimeter: {generic.perimeter()}")
101print(f" Area: {generic.area()}")102print(f" Perimeter: {generic⟨Shape D⟩.perimeter()}")103104print("\n=== Override Rules ===")105print("""1061. Same method name as parent1072. Same parameters (usually)1083. Different implementation1094. Child's version is called on child objects1105. Parent's version still exists in parent objects1116. No special keyword needed (unlike Java's @Override)112""")output Perimeter: 0 === Override Rules === 1. Same method name as parent 2. Same parameters (usually) 3. Different implementation 4. Child's version is called on child objects 5. Parent's version still exists in parent objects 6. No special keyword needed (unlike Java's @Override)
Same method name in child replaces parent's version.
Extend parent methods
Add to parent behavior instead of replacing it.
# Extending Parent Methods with super()
class Logger:
"""Base logger class."""
def __init__(self):
self.logs = []
def log(self, message):
"""Basic logging - just store message."""
entry = f"LOG: {message}"
self.logs.append(entry)
return entry
class TimestampLogger(Logger):
"""Logger that adds timestamps."""
def log(self, message):
# Add timestamp, then call parent
from datetime import datetime
timestamp = datetime.now().strftime("%H:%M:%S")
timestamped_message = f"[{timestamp}] {message}"
# Call parent's log with enhanced message
return super().log(timestamped_message)
class LevelLogger(Logger):
"""Logger with severity levels."""
def log(self, message, level="INFO"):
# Add level prefix, then call parent
leveled_message = f"{level}: {message}"
return super().log(leveled_message)
# Convenience methods
def info(self, message):
return self.log(message, "INFO")
def warning(self, message):
return self.log(message, "WARNING")
def error(self, message):
return self.log(message, "ERROR")
class CountingLogger(Logger):
"""Logger that counts messages."""
def __init__(self):
super().__init__()
self.count = 0
def log(self, message):
self.count += 1
# Extend message with count
numbered_message = f"#{self.count} {message}"
return super().log(numbered_message)
class FullFeaturedLogger(Logger):
"""Logger combining multiple features."""
def __init__(self, name):
super().__init__()
self.name = name
self.count = 0
def log(self, message, level="INFO"):
from datetime import datetime
self.count += 1
# Build full formatted message
timestamp = datetime.now().strftime("%H:%M:%S")
formatted = f"[{timestamp}] [{self.name}] #{self.count} {level}: {message}"
# Still use parent's storage mechanism
return super().log(formatted)
# Demonstration
print("=== Extending Parent Methods ===\n")
# Basic logger
print("--- Basic Logger ---")
basic = Logger()
print(basic.log("Hello"))
print(basic.log("World"))
print(f"Total logs: {len(basic.logs)}")
print("\n--- Timestamp Logger ---")
ts_logger = TimestampLogger()
print(ts_logger.log("Application started"))
print(ts_logger.log("Processing data"))
print(f"Logs stored: {ts_logger.logs}")
print("\n--- Level Logger ---")
level_logger = LevelLogger()
print(level_logger.info("Normal operation"))
print(level_logger.warning("Low disk space"))
print(level_logger.error("Connection failed"))
print("\n--- Counting Logger ---")
count_logger = CountingLogger()
print(count_logger.log("First message"))
print(count_logger.log("Second message"))
print(count_logger.log("Third message"))
print(f"Total count: {count_logger.count}")
print("\n--- Full Featured Logger ---")
app_logger = FullFeaturedLogger("APP")
print(app_logger.log("Started", "INFO"))
print(app_logger.log("Processing", "DEBUG"))
print(app_logger.log("Something wrong", "ERROR"))
print("\n=== Extend vs Override ===")
print("""
OVERRIDE: Replace parent's behavior completely
def method(self):
# all new code
EXTEND: Add to parent's behavior
def method(self):
# do something extra
super().method() # then call parent
# optionally do more
Benefits of extending:
1. Reuse parent's logic
2. Add functionality without duplicating code
3. Parent changes automatically apply
4. Can pre-process OR post-process
""")
"""Base logger class."""
3class Logger: #?loggerclass4 """Base logger class."""5 6 def __init__(self): #?loggerinit7 self.logs = [] #?logslist8 9 def log(self, message): #?logmethod10 """Basic logging - just store message."""11 entry = f"LOG: {message}" #?basicentry12 self.logs.append(entry)13 return entry141516class TimestampLogger(Logger): #?timestampclass17 """Logger that adds timestamps."""18 19 def log(self, message): #?timestamplog20 # Add timestamp, then call parent #?addtimestamp21 from datetime import datetime22 timestamp = datetime.now().strftime("%H:%M:%S") #?gettimestamp23 timestamped_message = f"[{timestamp}] {message}" #?formatmsg24 25 # Call parent's log with enhanced message #?callparent26 return super().log(timestamped_message) #?superlog272829class LevelLogger(Logger): #?levelclass30 """Logger with severity levels."""31 32 def log(self, message, level="INFO"): #?levellog33 # Add level prefix, then call parent #?addlevel34 leveled_message = f"{level}: {message}" #?levelmsg35 return super().log(leveled_message)36 37 # Convenience methods #?convenience38 def info(self, message): #?infomethod39 return self.log(message, "INFO")40 41 def warning(self, message): #?warningmethod42 return self.log(message, "WARNING")43 44 def error(self, message): #?errormethod45 return self.log(message, "ERROR")464748class CountingLogger(Logger): #?countingclass49 """Logger that counts messages."""50 51 def __init__(self): #?countinginit52 super().__init__() #?superinit53 self.count = 0 #?initcount54 55 def log(self, message): #?countinglog56 self.count += 1 #?increment57 # Extend message with count #?extendcount58 numbered_message = f"#{self.count} {message}"59 return super().log(numbered_message)606162class FullFeaturedLogger(Logger): #?fullclass63 """Logger combining multiple features."""64 65 def __init__(self, name): #?fullinit66 super().__init__()67 self.name = name68 self.count = 069 70 def log(self, message, level="INFO"): #?fulllog71 from datetime import datetime72 self.count += 173 74 # Build full formatted message #?buildmsg75 timestamp = datetime.now().strftime("%H:%M:%S")76 formatted = f"[{timestamp}] [{self.name}] #{self.count} {level}: {message}"77 78 # Still use parent's storage mechanism #?useparent79 return super().log(formatted)808182# Demonstration83print("=== Extending Parent Methods ===\n")8485# Basic logger #?basicdemo86print("--- Basic Logger ---")87basic = Logger() #?createbasic88print(basic.log("Hello"))output=== Extending Parent Methods === --- Basic Logger ---self.logs ← []
pass 1 of 56def __init__(self⟨Logger A⟩): #?loggerinit7 self.logs→ [] = [] #?logslistAll 5 passes — pass 1 is the card above pass selfself.logs1 ⟨Logger A⟩ [] 2 ⟨TimestampLogger B⟩ [] 3 ⟨LevelLogger C⟩ [] 4 ⟨CountingLogger D⟩ [] 5 ⟨FullFeaturedLogger E⟩ [] basic ← ⟨Logger A⟩
86print("--- Basic Logger ---")87basic→ ⟨Logger A⟩ = Logger() #?createbasic88print(basic⟨Logger A⟩.log("Hello"))89print(basic.log("World"))entry ← LOG: Hello, self.logs ← ['LOG: Hello']
pass 1 of 139def log(self⟨Logger A⟩, messageHello): #?logmethod10 """Basic logging - just store message."""11 entry→ LOG: Hello = f"LOG: {messageHello}" #?basicentry12 self.logs→ ['LOG: Hello'].append(entryLOG: Hello)13 return entryLOG: Hello13 passes — pass 1 is the card above pass selfmessageentryself.logs1 ⟨Logger A⟩ Hello LOG: Hello [] → ['LOG: Hello'] 2 ⟨Logger A⟩ World LOG: World ['LOG: Hello'] → ['LOG: Hello', 'LOG: World'] 3 ⟨TimestampLogger B⟩ [22:54:22] Application started LOG: [22:54:22] Application started [] → ['LOG: [22:54:22] Application started'] 4 ⟨TimestampLogger B⟩ [22:54:22] Processing data LOG: [22:54:22] Processing data ['LOG: [22:54:22] Application started'] → ['LOG: [22:54:22] Application started', 'LOG: [22:54:22] Processing data'] 5 ⟨LevelLogger C⟩ INFO: Normal operation LOG: INFO: Normal operation [] → ['LOG: INFO: Normal operation'] 6 ⟨LevelLogger C⟩ WARNING: Low disk space LOG: WARNING: Low disk space ['LOG: INFO: Normal operation'] → ['LOG: INFO: Normal operation', 'LOG: WARNING: Low disk space'] 7 ⟨LevelLogger C⟩ ERROR: Connection failed LOG: ERROR: Connection failed ['LOG: INFO: Normal operation', 'LOG: WARNING: Low disk space'] → ['LOG: INFO: Normal operation', 'LOG: WARNING: Low disk space', 'LOG: ERROR: Connection failed'] 8 ⟨CountingLogger D⟩ #1 First message LOG: #1 First message [] → ['LOG: #1 First message'] 9 ⟨CountingLogger D⟩ #2 Second message LOG: #2 Second message ['LOG: #1 First message'] → ['LOG: #1 First message', 'LOG: #2 Second message'] ⋯ 2 more passes ⋯ 12 ⟨FullFeaturedLogger E⟩ [22:54:22] [APP] #2 DEBUG: Processing LOG: [22:54:22] [APP] #2 DEBUG: Processing ['LOG: [22:54:22] [APP] #1 INFO: Started'] → ['LOG: [22:54:22] [APP] #1 INFO: Started', 'LOG: [22:54:22] [APP] #2 DEBUG: Processing'] 13 ⟨FullFeaturedLogger E⟩ [22:54:22] [APP] #3 ERROR: Something wrong LOG: [22:54:22] [APP] #3 ERROR: Something wrong ['LOG: [22:54:22] [APP] #1 INFO: Started', 'LOG: [22:54:22] [APP] #2 DEBUG: Processing'] → ['LOG: [22:54:22] [APP] #1 INFO: Started', 'LOG: [22:54:22] [APP] #2 DEBUG: Processing', 'LOG: [22:54:22] [APP] #3 ERROR: Something wrong'] print(basic.log("Hello"))
87basic = Logger() #?createbasic88print(basic⟨Logger A⟩.log("Hello"))89print(basic⟨Logger A⟩.log("World"))90print(f"Total logs: {len(basic.logs)}")outputLOG: Helloprint(basic.log("World"))
88print(basic.log("Hello"))89print(basic⟨Logger A⟩.log("World"))90print(f"Total logs: {len(basic.logs['LOG: Hello', 'LOG: World'])}")9192print("\n--- Timestamp Logger ---")93ts_logger = TimestampLogger() #?createts94print(ts_logger.log("Application started")) #?tslogoutputLOG: World Total logs: 2 --- Timestamp Logger ---ts_logger ← ⟨TimestampLogger B⟩
92print("\n--- Timestamp Logger ---")93ts_logger→ ⟨TimestampLogger B⟩ = TimestampLogger() #?createts94print(ts_logger⟨TimestampLogger B⟩.log("Application started")) #?tslog95print(ts_logger.log("Processing data"))timestamp ← 22:54:22, timestamped_message ← [22:54:22] Application started
pass 1 of 219def log(self⟨TimestampLogger B⟩, messageApplication started): #?timestamplog20 # Add timestamp, then call parent #?addtimestamp21 from datetime import datetime22 timestamp→ 22:54:22 = datetime<class 'datetime.datetime'>.now().strftime("%H:%M:%S") #?gettimestamp23 timestamped_message→ [22:54:22] Application started = f"[{timestamp22:54:22}] {messageApplication started}" #?formatmsg24 25 # Call parent's log with enhanced message #?callparent26 return super().log(timestamped_message[22:54:22] Application started) #?superlogprint(ts_logger.log("Application started")) #?tslog
93ts_logger = TimestampLogger() #?createts94print(ts_logger⟨TimestampLogger B⟩.log("Application started")) #?tslog95print(ts_logger⟨TimestampLogger B⟩.log("Processing data"))96print(f"Logs stored: {ts_logger.logs}")outputLOG: [22:54:22] Application startedtimestamp ← 22:54:22, timestamped_message ← [22:54:22] Processing data
pass 2 of 219def log(self⟨TimestampLogger B⟩, messageProcessing data): #?timestamplog20 # Add timestamp, then call parent #?addtimestamp21 from datetime import datetime22 timestamp→ 22:54:22 = datetime<class 'datetime.datetime'>.now().strftime("%H:%M:%S") #?gettimestamp23 timestamped_message→ [22:54:22] Processing data = f"[{timestamp22:54:22}] {messageProcessing data}" #?formatmsg24 25 # Call parent's log with enhanced message #?callparent26 return super().log(timestamped_message[22:54:22] Processing data) #?superlogprint(ts_logger.log("Processing data"))
94print(ts_logger.log("Application started")) #?tslog95print(ts_logger⟨TimestampLogger B⟩.log("Processing data"))96print(f"Logs stored: {ts_logger.logs['LOG: [22:54:22] Application started', 'LOG: [22:54:22] Processing data']}")9798print("\n--- Level Logger ---")99level_logger = LevelLogger() #?createlevel100print(level_logger.info("Normal operation")) #?levelinfooutputLOG: [22:54:22] Processing data Logs stored: ['LOG: [22:54:22] Application started', 'LOG: [22:54:22] Processing data'] --- Level Logger ---level_logger ← ⟨LevelLogger C⟩
98print("\n--- Level Logger ---")99level_logger→ ⟨LevelLogger C⟩ = LevelLogger() #?createlevel100print(level_logger⟨LevelLogger C⟩.info("Normal operation")) #?levelinfo101print(level_logger.warning("Low disk space")) #?levelwarndef info(self, message): #?infomethod
37# Convenience methods #?convenience38def info(self⟨LevelLogger C⟩, messageNormal operation): #?infomethod39 return self.log(messageNormal operation, "INFO")leveled_message ← INFO: Normal operation
pass 1 of 332def log(self⟨LevelLogger C⟩, messageNormal operation, levelINFO="INFO"): #?levellog33 # Add level prefix, then call parent #?addlevel34 leveled_message→ INFO: Normal operation = f"{levelINFO}: {messageNormal operation}" #?levelmsg35 return super().log(leveled_messageINFO: Normal operation)All 3 passes — pass 1 is the card above pass messagelevelleveled_message1 Normal operation INFO INFO: Normal operation 2 Low disk space WARNING WARNING: Low disk space 3 Connection failed ERROR ERROR: Connection failed print(level_logger.info("Normal operation")) #?levelinfo
99level_logger = LevelLogger() #?createlevel100print(level_logger⟨LevelLogger C⟩.info("Normal operation")) #?levelinfo101print(level_logger⟨LevelLogger C⟩.warning("Low disk space")) #?levelwarn102print(level_logger.error("Connection failed")) #?levelerroroutputLOG: INFO: Normal operationdef warning(self, message): #?warningmethod
41def warning(self⟨LevelLogger C⟩, messageLow disk space): #?warningmethod42 return self.log(messageLow disk space, "WARNING")print(level_logger.warning("Low disk space")) #?levelwarn
100print(level_logger.info("Normal operation")) #?levelinfo101print(level_logger⟨LevelLogger C⟩.warning("Low disk space")) #?levelwarn102print(level_logger⟨LevelLogger C⟩.error("Connection failed")) #?levelerroroutputLOG: WARNING: Low disk spacedef error(self, message): #?errormethod
44def error(self⟨LevelLogger C⟩, messageConnection failed): #?errormethod45 return self.log(messageConnection failed, "ERROR")print(level_logger.error("Connection failed")) #?levelerror
101print(level_logger.warning("Low disk space")) #?levelwarn102print(level_logger⟨LevelLogger C⟩.error("Connection failed")) #?levelerror103104print("\n--- Counting Logger ---")105count_logger = CountingLogger() #?createcount106print(count_logger.log("First message")) #?countlogoutputLOG: ERROR: Connection failed --- Counting Logger ---def __init__(self): #?countinginit
51def __init__(self⟨CountingLogger D⟩): #?countinginit52 super().__init__() #?superinit53 self.count = 0 #?initcountself.count ← 0
52super().__init__() #?superinit53self.count→ 0 = 0 #?initcountcount_logger ← ⟨CountingLogger D⟩
104print("\n--- Counting Logger ---")105count_logger→ ⟨CountingLogger D⟩ = CountingLogger() #?createcount106print(count_logger⟨CountingLogger D⟩.log("First message")) #?countlog107print(count_logger.log("Second message"))self.count ← 1, numbered_message ← #1 First message
pass 1 of 355def log(self⟨CountingLogger D⟩, messageFirst message): #?countinglog56 self.count→ 1 += 1 #?increment57 # Extend message with count #?extendcount58 numbered_message→ #1 First message = f"#{self.count1} {messageFirst message}"59 return super().log(numbered_message#1 First message)All 3 passes — pass 1 is the card above pass messageself.countnumbered_message1 First message 0 → 1 #1 First message 2 Second message 1 → 2 #2 Second message 3 Third message 2 → 3 #3 Third message print(count_logger.log("First message")) #?countlog
105count_logger = CountingLogger() #?createcount106print(count_logger⟨CountingLogger D⟩.log("First message")) #?countlog107print(count_logger⟨CountingLogger D⟩.log("Second message"))108print(count_logger.log("Third message"))outputLOG: #1 First messageprint(count_logger.log("Second message"))
106print(count_logger.log("First message")) #?countlog107print(count_logger⟨CountingLogger D⟩.log("Second message"))108print(count_logger⟨CountingLogger D⟩.log("Third message"))109print(f"Total count: {count_logger.count}")outputLOG: #2 Second messageprint(count_logger.log("Third message"))
107print(count_logger.log("Second message"))108print(count_logger⟨CountingLogger D⟩.log("Third message"))109print(f"Total count: {count_logger.count3}")110111print("\n--- Full Featured Logger ---")112app_logger = FullFeaturedLogger("APP") #?createfull113print(app_logger.log("Started", "INFO"))outputLOG: #3 Third message Total count: 3 --- Full Featured Logger ---def __init__(self, name): #?fullinit
65def __init__(self⟨FullFeaturedLogger E⟩, nameAPP): #?fullinit66 super().__init__()67 self.name = nameself.name ← APP, self.count ← 0
66super().__init__()67self.name→ APP = nameAPP68self.count→ 0 = 0app_logger ← ⟨FullFeaturedLogger E⟩
111print("\n--- Full Featured Logger ---")112app_logger→ ⟨FullFeaturedLogger E⟩ = FullFeaturedLogger("APP") #?createfull113print(app_logger⟨FullFeaturedLogger E⟩.log("Started", "INFO"))114print(app_logger.log("Processing", "DEBUG"))self.count ← 1, timestamp ← 22:54:22, formatted ← [22:54:22] [APP] #1 INFO: Started
pass 1 of 370def log(self⟨FullFeaturedLogger E⟩, messageStarted, levelINFO="INFO"): #?fulllog71 from datetime import datetime72 self.count→ 1 += 173 74 # Build full formatted message #?buildmsg75 timestamp→ 22:54:22 = datetime<class 'datetime.datetime'>.now().strftime("%H:%M:%S")76 formatted→ [22:54:22] [APP] #1 INFO: Started = f"[{timestamp22:54:22}] [{self.nameAPP}] #{self.count1} {levelINFO}: {messageStarted}"77 78 # Still use parent's storage mechanism #?useparent79 return super().log(formatted[22:54:22] [APP] #1 INFO: Started)All 3 passes — pass 1 is the card above pass messagelevelself.counttimestampformatted1 Started INFO 0 → 1 22:54:22 [22:54:22] [APP] #1 INFO: Started 2 Processing DEBUG 1 → 2 22:54:22 [22:54:22] [APP] #2 DEBUG: Processing 3 Something wrong ERROR 2 → 3 22:54:22 [22:54:22] [APP] #3 ERROR: Something wrong print(app_logger.log("Started", "INFO"))
112app_logger = FullFeaturedLogger("APP") #?createfull113print(app_logger⟨FullFeaturedLogger E⟩.log("Started", "INFO"))114print(app_logger⟨FullFeaturedLogger E⟩.log("Processing", "DEBUG"))115print(app_logger.log("Something wrong", "ERROR"))outputLOG: [22:54:22] [APP] #1 INFO: Startedprint(app_logger.log("Processing", "DEBUG"))
113print(app_logger.log("Started", "INFO"))114print(app_logger⟨FullFeaturedLogger E⟩.log("Processing", "DEBUG"))115print(app_logger⟨FullFeaturedLogger E⟩.log("Something wrong", "ERROR"))outputLOG: [22:54:22] [APP] #2 DEBUG: Processingprint(app_logger.log("Something wrong", "ERROR"))
114print(app_logger.log("Processing", "DEBUG"))115print(app_logger⟨FullFeaturedLogger E⟩.log("Something wrong", "ERROR"))116117print("\n=== Extend vs Override ===")118print("""119OVERRIDE: Replace parent's behavior completely120 def method(self):121 # all new code122123EXTEND: Add to parent's behavior124 def method(self):125 # do something extra126 super().method() # then call parent127 # optionally do more128129Benefits of extending:1301. Reuse parent's logic1312. Add functionality without duplicating code1323. Parent changes automatically apply1334. Can pre-process OR post-process134""")outputLOG: [22:54:22] [APP] #3 ERROR: Something wrong === Extend vs Override === OVERRIDE: Replace parent's behavior completely def method(self): # all new code EXTEND: Add to parent's behavior def method(self): # do something extra super().method() # then call parent # optionally do more Benefits of extending: 1. Reuse parent's logic 2. Add functionality without duplicating code 3. Parent changes automatically apply 4. Can pre-process OR post-process
Call super().method() then add more logic. Best of both worlds.
Type checking with isinstance
Check inheritance relationships at runtime.
# isinstance() and issubclass()
class Vehicle:
"""Base class for all vehicles."""
def __init__(self, brand):
self.brand = brand
def start(self):
return f"{self.brand} starting..."
class Car(Vehicle):
"""Car extends Vehicle."""
def __init__(self, brand, num_doors):
super().__init__(brand)
self.num_doors = num_doors
def drive(self):
return f"{self.brand} car driving"
class ElectricCar(Car):
"""ElectricCar extends Car."""
def __init__(self, brand, num_doors, battery_capacity):
super().__init__(brand, num_doors)
self.battery_capacity = battery_capacity
def charge(self):
return f"Charging {self.brand}"
class Motorcycle(Vehicle):
"""Motorcycle extends Vehicle."""
def __init__(self, brand, cc):
super().__init__(brand)
self.cc = cc
def wheelie(self):
return f"{self.brand} doing a wheelie!"
print("=== isinstance() and issubclass() ===\n")
# Create instances
my_car = Car("Toyota", 4)
my_tesla = ElectricCar("Tesla", 4, 100)
my_bike = Motorcycle("Harley", 1200)
print("--- isinstance() checks ---")
# isinstance(object, class)
print(f"my_car is Car: {isinstance(my_car, Car)}")
print(f"my_car is Vehicle: {isinstance(my_car, Vehicle)}")
print(f"my_car is ElectricCar: {isinstance(my_car, ElectricCar)}")
print()
# Tesla checks
print(f"my_tesla is ElectricCar: {isinstance(my_tesla, ElectricCar)}")
print(f"my_tesla is Car: {isinstance(my_tesla, Car)}")
print(f"my_tesla is Vehicle: {isinstance(my_tesla, Vehicle)}")
print(f"my_tesla is Motorcycle: {isinstance(my_tesla, Motorcycle)}")
print()
# Check multiple types
print(f"my_car is (Car, Motorcycle): {isinstance(my_car, (Car, Motorcycle))}")
print(f"my_bike is (Car, Motorcycle): {isinstance(my_bike, (Car, Motorcycle))}")
print("\n--- issubclass() checks ---")
# issubclass(class, class)
print(f"Car is subclass of Vehicle: {issubclass(Car, Vehicle)}")
print(f"ElectricCar is subclass of Car: {issubclass(ElectricCar, Car)}")
print(f"ElectricCar is subclass of Vehicle: {issubclass(ElectricCar, Vehicle)}")
print(f"Car is subclass of Car: {issubclass(Car, Car)}")
print(f"Car is subclass of Motorcycle: {issubclass(Car, Motorcycle)}")
print("\n--- Practical use: Processing different types ---")
# List of mixed vehicles
vehicles = [my_car, my_tesla, my_bike]
for v in vehicles:
print(f"\n{v.brand}:")
print(f" {v.start()}")
# Type-specific behavior
if isinstance(v, ElectricCar):
print(f" {v.charge()}")
if isinstance(v, Car):
print(f" {v.drive()}")
if isinstance(v, Motorcycle):
print(f" {v.wheelie()}")
print("\n--- Type hierarchy ---")
print(f"ElectricCar MRO: {ElectricCar.__mro__}")
print("\n=== isinstance vs type() ===")
print("""
isinstance(obj, cls):
- Returns True if obj is instance of cls OR subclass
- Preferred for inheritance hierarchies
- Can check multiple types with tuple
type(obj) == cls:
- Returns True only for exact type match
- Does NOT consider inheritance
- Use when exact type matters
Example:
isinstance(my_tesla, Car) # True (Tesla IS-A Car)
type(my_tesla) == Car # False (exact type is ElectricCar)
""")
# Demonstrate difference
print("--- isinstance vs type ===")
print(f"isinstance(my_tesla, Car): {isinstance(my_tesla, Car)}")
print(f"type(my_tesla) == Car: {type(my_tesla) == Car}")
print(f"type(my_tesla) == ElectricCar: {type(my_tesla) == ElectricCar}")
"""Base class for all vehicles."""
3class Vehicle: #?vehicleclass4 """Base class for all vehicles."""5 def __init__(self, brand):6 self.brand = brand7 8 def start(self):9 return f"{self.brand} starting..."101112class Car(Vehicle): #?carclass13 """Car extends Vehicle."""14 def __init__(self, brand, num_doors):15 super().__init__(brand)16 self.num_doors = num_doors17 18 def drive(self):19 return f"{self.brand} car driving"202122class ElectricCar(Car): #?electricclass23 """ElectricCar extends Car."""24 def __init__(self, brand, num_doors, battery_capacity):25 super().__init__(brand, num_doors)26 self.battery_capacity = battery_capacity27 28 def charge(self):29 return f"Charging {self.brand}"303132class Motorcycle(Vehicle): #?motorcycleclass33 """Motorcycle extends Vehicle."""34 def __init__(self, brand, cc):35 super().__init__(brand)36 self.cc = cc37 38 def wheelie(self):39 return f"{self.brand} doing a wheelie!"404142print("=== isinstance() and issubclass() ===\n")4344# Create instances #?createvehicles45my_car = Car("Toyota", 4) #?carinstance46my_tesla = ElectricCar("Tesla", 4, 100) #?teslainstanceoutput=== isinstance() and issubclass() ===def __init__(self, brand, num_doors):
pass 1 of 213"""Car extends Vehicle."""14def __init__(self⟨Car A⟩, brandToyota, num_doors4):15 super().__init__(brand)16 self.num_doors = num_doorsself.brand ← Toyota
pass 1 of 34"""Base class for all vehicles."""5def __init__(self⟨Car A⟩, brandToyota):6 self.brand→ Toyota = brandToyotaAll 3 passes — pass 1 is the card above pass selfbrandself.brand1 ⟨Car A⟩ Toyota Toyota 2 ⟨ElectricCar B⟩ Tesla Tesla 3 ⟨Motorcycle C⟩ Harley Harley self.num_doors ← 4
15super().__init__(brand)16self.num_doors→ 4 = num_doors4my_car ← ⟨Car A⟩
44# Create instances #?createvehicles45my_car→ ⟨Car A⟩ = Car("Toyota", 4) #?carinstance46my_tesla = ElectricCar("Tesla", 4, 100) #?teslainstance47my_bike = Motorcycle("Harley", 1200) #?bikeinstancedef __init__(self, brand, num_doors, battery_capacity):
23"""ElectricCar extends Car."""24def __init__(self⟨ElectricCar B⟩, brandTesla, num_doors4, battery_capacity100):25 super().__init__(brand, num_doors)26 self.battery_capacity = battery_capacitydef __init__(self, brand, num_doors):
pass 2 of 213"""Car extends Vehicle."""14def __init__(self⟨ElectricCar B⟩, brandTesla, num_doors4):15 super().__init__(brand)16 self.num_doors = num_doorsself.num_doors ← 4
15super().__init__(brand)16self.num_doors→ 4 = num_doors4self.battery_capacity ← 100
25super().__init__(brand, num_doors)26self.battery_capacity→ 100 = battery_capacity100my_tesla ← ⟨ElectricCar B⟩
45my_car = Car("Toyota", 4) #?carinstance46my_tesla→ ⟨ElectricCar B⟩ = ElectricCar("Tesla", 4, 100) #?teslainstance47my_bike = Motorcycle("Harley", 1200) #?bikeinstancedef __init__(self, brand, cc):
33"""Motorcycle extends Vehicle."""34def __init__(self⟨Motorcycle C⟩, brandHarley, cc1200):35 super().__init__(brand)36 self.cc = ccself.cc ← 1200
35super().__init__(brand)36self.cc→ 1200 = cc1200my_bike ← ⟨Motorcycle C⟩, vehicles ← [⟨Car A⟩, ⟨ElectricCar B⟩, ⟨Motorcycle C⟩]
46my_tesla = ElectricCar("Tesla", 4, 100) #?teslainstance47my_bike→ ⟨Motorcycle C⟩ = Motorcycle("Harley", 1200) #?bikeinstance4849print("--- isinstance() checks ---")5051# isinstance(object, class) #?isinstancedemo52print(f"my_car is Car: {isinstance(my_car⟨Car A⟩, Car<class '__main__.Car'>)}") #?cariscar53print(f"my_car is Vehicle: {isinstance(my_car⟨Car A⟩, Vehicle<class '__main__.Vehicle'>)}") #?carisvehicle54print(f"my_car is ElectricCar: {isinstance(my_car⟨Car A⟩, ElectricCar<class '__main__.ElectricCar'>)}") #?cariselectric5556print()5758# Tesla checks #?teslacheck59print(f"my_tesla is ElectricCar: {isinstance(my_tesla⟨ElectricCar B⟩, ElectricCar<class '__main__.ElectricCar'>)}") #?teslaiselectric60print(f"my_tesla is Car: {isinstance(my_tesla⟨ElectricCar B⟩, Car<class '__main__.Car'>)}") #?teslaiscar61print(f"my_tesla is Vehicle: {isinstance(my_tesla⟨ElectricCar B⟩, Vehicle<class '__main__.Vehicle'>)}") #?teslaisvehicle62print(f"my_tesla is Motorcycle: {isinstance(my_tesla⟨ElectricCar B⟩, Motorcycle<class '__main__.Motorcycle'>)}") #?teslaisbike6364print()6566# Check multiple types #?multipletypes67print(f"my_car is (Car, Motorcycle): {isinstance(my_car⟨Car A⟩, (Car<class '__main__.Car'>, Motorcycle<class '__main__.Motorcycle'>))}") #?caristuple68print(f"my_bike is (Car, Motorcycle): {isinstance(my_bike⟨Motorcycle C⟩, (Car<class '__main__.Car'>, Motorcycle<class '__main__.Motorcycle'>))}") #?bikeistuple6970print("\n--- issubclass() checks ---")7172# issubclass(class, class) #?issubclassdemo73print(f"Car is subclass of Vehicle: {issubclass(Car<class '__main__.Car'>, Vehicle<class '__main__.Vehicle'>)}") #?carsubvehicle74print(f"ElectricCar is subclass of Car: {issubclass(ElectricCar<class '__main__.ElectricCar'>, Car<class '__main__.Car'>)}") #?electricsubcar75print(f"ElectricCar is subclass of Vehicle: {issubclass(ElectricCar<class '__main__.ElectricCar'>, Vehicle<class '__main__.Vehicle'>)}") #?electricsubvehicle76print(f"Car is subclass of Car: {issubclass(Car<class '__main__.Car'>, Car)}") #?carsubcar77print(f"Car is subclass of Motorcycle: {issubclass(Car<class '__main__.Car'>, Motorcycle<class '__main__.Motorcycle'>)}") #?carsubmotorcycle7879print("\n--- Practical use: Processing different types ---")8081# List of mixed vehicles #?mixedlist82vehicles→ [⟨Car A⟩, ⟨ElectricCar B⟩, ⟨Motorcycle C⟩] = [my_car⟨Car A⟩, my_tesla⟨ElectricCar B⟩, my_bike⟨Motorcycle C⟩] #?vehiclelistoutput--- isinstance() checks --- my_car is Car: True my_car is Vehicle: True my_car is ElectricCar: False my_tesla is ElectricCar: True my_tesla is Car: True my_tesla is Vehicle: True my_tesla is Motorcycle: False my_car is (Car, Motorcycle): True my_bike is (Car, Motorcycle): True --- issubclass() checks --- Car is subclass of Vehicle: True ElectricCar is subclass of Car: True ElectricCar is subclass of Vehicle: True Car is subclass of Car: True Car is subclass of Motorcycle: False --- Practical use: Processing different types ---for v in vehicles: #?iteratevehicles
pass 1 of 384for v⟨Car A⟩ in vehicles[⟨Car A⟩, ⟨ElectricCar B⟩, ⟨Motorcycle C⟩]: #?iteratevehicles85 print(f"\n{v.brandToyota}:")86 print(f" {v⟨Car A⟩.start()}") #?callstartoutput Toyota:All 3 passes — pass 1 is the card above pass vv.brand1 ⟨Car A⟩ Toyota 2 ⟨ElectricCar B⟩ Tesla 3 ⟨Motorcycle C⟩ Harley def start(self):
pass 1 of 38def start(self⟨Car A⟩):9 return f"{self.brandToyota} starting..."All 3 passes — pass 1 is the card above pass selfself.brand1 ⟨Car A⟩ Toyota 2 ⟨ElectricCar B⟩ Tesla 3 ⟨Motorcycle C⟩ Harley print(f" {v.start()}") #?callstart
85print(f"\n{v.brand}:")86print(f" {v⟨Car A⟩.start()}") #?callstartoutput Toyota starting...if isinstance(v, Car): #?checkcar
pass 1 of 292if isinstance(v⟨Car A⟩, Car<class '__main__.Car'>): #?checkcar93 print(f" {v⟨Car A⟩.drive()}") #?calldrivedef drive(self):
pass 1 of 218def drive(self⟨Car A⟩):19 return f"{self.brandToyota} car driving"print(f" {v.drive()}") #?calldrive
92if isinstance(v, Car): #?checkcar93 print(f" {v⟨Car A⟩.drive()}") #?calldriveoutput Toyota car drivingprint(f" {v.start()}") #?callstart
85print(f"\n{v.brand}:")86print(f" {v⟨ElectricCar B⟩.start()}") #?callstartoutput Tesla starting...if isinstance(v, ElectricCar): #?checkelectric
88# Type-specific behavior #?typespecific89if isinstance(v⟨ElectricCar B⟩, ElectricCar<class '__main__.ElectricCar'>): #?checkelectric90 print(f" {v⟨ElectricCar B⟩.charge()}") #?callchargedef charge(self):
28def charge(self⟨ElectricCar B⟩):29 return f"Charging {self.brandTesla}"print(f" {v.charge()}") #?callcharge
89if isinstance(v, ElectricCar): #?checkelectric90 print(f" {v⟨ElectricCar B⟩.charge()}") #?callchargeoutput Charging Teslaif isinstance(v, Car): #?checkcar
pass 2 of 292if isinstance(v⟨ElectricCar B⟩, Car<class '__main__.Car'>): #?checkcar93 print(f" {v⟨ElectricCar B⟩.drive()}") #?calldrivedef drive(self):
pass 2 of 218def drive(self⟨ElectricCar B⟩):19 return f"{self.brandTesla} car driving"print(f" {v.drive()}") #?calldrive
92if isinstance(v, Car): #?checkcar93 print(f" {v⟨ElectricCar B⟩.drive()}") #?calldriveoutput Tesla car drivingprint(f" {v.start()}") #?callstart
85print(f"\n{v.brand}:")86print(f" {v⟨Motorcycle C⟩.start()}") #?callstartoutput Harley starting...if isinstance(v, Motorcycle): #?checkmotorcycle
95if isinstance(v⟨Motorcycle C⟩, Motorcycle<class '__main__.Motorcycle'>): #?checkmotorcycle96 print(f" {v⟨Motorcycle C⟩.wheelie()}") #?callwheeliedef wheelie(self):
38def wheelie(self⟨Motorcycle C⟩):39 return f"{self.brandHarley} doing a wheelie!"print(f" {v.wheelie()}") #?callwheelie
95if isinstance(v, Motorcycle): #?checkmotorcycle96 print(f" {v⟨Motorcycle C⟩.wheelie()}") #?callwheelieoutput Harley doing a wheelie!print(f"ElectricCar MRO: {ElectricCar.__mro__}") #?mro
98print("\n--- Type hierarchy ---")99print(f"ElectricCar MRO: {ElectricCar.__mro__(<class '__main__.ElectricCar'>, <class '__main__.Car'>, <class '__main__.Vehicle'>, <class 'object'>)}") #?mro100101print("\n=== isinstance vs type() ===")102print("""103isinstance(obj, cls):104 - Returns True if obj is instance of cls OR subclass105 - Preferred for inheritance hierarchies106 - Can check multiple types with tuple107108type(obj) == cls:109 - Returns True only for exact type match110 - Does NOT consider inheritance111 - Use when exact type matters112113Example:114 isinstance(my_tesla, Car) # True (Tesla IS-A Car)115 type(my_tesla) == Car # False (exact type is ElectricCar)116""")117118# Demonstrate difference #?typedemo119print("--- isinstance vs type ===")120print(f"isinstance(my_tesla, Car): {isinstance(my_tesla⟨ElectricCar B⟩, Car<class '__main__.Car'>)}") #?isinstancetesla121print(f"type(my_tesla) == Car: {type(my_tesla⟨ElectricCar B⟩) == Car<class '__main__.Car'>}") #?typetesla122print(f"type(my_tesla) == ElectricCar: {type(my_tesla⟨ElectricCar B⟩) == ElectricCar<class '__main__.ElectricCar'>}") #?typeexactoutput --- Type hierarchy --- ElectricCar MRO: (<class '__main__.ElectricCar'>, <class '__main__.Car'>, <class '__main__.Vehicle'>, <class 'object'>) === isinstance vs type() === isinstance(obj, cls): - Returns True if obj is instance of cls OR subclass - Preferred for inheritance hierarchies - Can check multiple types with tuple type(obj) == cls: - Returns True only for exact type match - Does NOT consider inheritance - Use when exact type matters Example: isinstance(my_tesla, Car) # True (Tesla IS-A Car) type(my_tesla) == Car # False (exact type is ElectricCar) --- isinstance vs type === isinstance(my_tesla, Car): True type(my_tesla) == Car: False type(my_tesla) == ElectricCar: True
isinstance(obj, Class) checks if obj is instance of Class or subclass.
Exercise: practical.py
Build an employee hierarchy with inheritance