"In Python, inheritance isn't just about sharing code; it's about modeling 'is-a' relationships, creating a powerful, extensible hierarchy where specialized classes can gracefully build upon the foundations of their ancestors."- Gemini 2025
By the end of this lecture, you will be able to:
A class is a blueprint or template for creating objects. It defines attributes (data) and methods (functions) that objects of that type will have.
An object is an instance of a class - a specific realization of the blueprint with actual values.
# Basic class structure class Movie: def __init__(self, title, year): self.title = title self.year = year def display_info(self): return f"{self.title} ({self.year})" # Creating objects movie1 = Movie("The Matrix", 1999) movie2 = Movie("Inception", 2010)
When one class is a specialized version of another class, we use inheritance.
Dog
Animal
ActionMovie
Movie
Student
Person
class Child(Parent):
When one class has a component that is another class, we use composition.
Director
Car
Engine
Library
Books
class Movie: # Parent/Base class def __init__(self, title, year, genre): self.title = title self.year = year self.genre = genre def play(self): return f"Playing {self.title}" class ActionMovie(Movie): # Child/Derived class def __init__(self, title, year, lead_actor, budget): super().__init__(title, year, "Action") # Call parent constructor self.lead_actor = lead_actor self.budget = budget def explosive_scene(self): return f"{self.lead_actor} saves the day!"
Child classes can provide their own implementation of parent methods:
class DocumentaryMovie(Movie): def __init__(self, title, year, subject): super().__init__(title, year, "Documentary") self.subject = subject def play(self): # Override parent method return f"Now presenting the documentary: {self.title} about {self.subject}"
Instead of inheritance, we can build complex objects by combining simpler ones:
class Director: def __init__(self, name, birth_year): self.name = name self.birth_year = birth_year def __str__(self): return f"Director: {self.name}" class Actor: def __init__(self, name, birth_year): self.name = name self.birth_year = birth_year def __str__(self): return f"Actor: {self.name}" class Movie: def __init__(self, title, year, director): self.title = title self.year = year self.director = director # Movie HAS-A Director self.cast = [] # Movie HAS-A list of Actors def add_actor(self, actor): self.cast.append(actor) def get_credits(self): credits = f"{self.title} ({self.year})\n" credits += f"Directed by: {self.director.name}\n" credits += "Starring: " + ", ".join([actor.name for actor in self.cast]) return credits
You can use inheritance and composition together:
class StreamingMovie(Movie): # Inheritance: StreamingMovie IS-A Movie def __init__(self, title, year, director, platform, subscription_required): super().__init__(title, year, director) # Call parent constructor self.platform = platform self.subscription_required = subscription_required def stream(self): if self.subscription_required: return f"Subscribe to {self.platform} to watch {self.title}" else: return f"Now streaming {self.title} on {self.platform}"
__str__
__repr__
super()
# Composition classes (HAS-A relationships) class Director: def __init__(self, name, birth_year, nationality='Unknown'): self.name = name self.birth_year = birth_year self.nationality = nationality def __str__(self): return f'{self.name} ({self.nationality})' class Actor: def __init__(self, name, birth_year): self.name = name self.birth_year = birth_year def __str__(self): return self.name # Base class class Movie: def __init__(self, title, year, director, genre='Unknown'): self.title = title self.year = year self.director = director # HAS-A Director (composition) self.genre = genre self.cast = [] # HAS-A list of Actors (composition) self.rating = None def add_actor(self, actor): self.cast.append(actor) def set_rating(self, rating): if 0 <= rating <= 10: self.rating = rating else: print('Rating must be between 0 and 10') def play(self): return f'Now playing: {self.title}' def get_info(self): info = f'\n=== {self.title} ({self.year}) ===\n' info += f'Genre: {self.genre}\n' info += f'Director: {self.director}\n' if self.cast: info += 'Cast: {'.join(str(actor) for actor in self.cast) + '\n' if self.rating: info += f'Rating: {self.rating}/10\n' return info def __str__(self): return f'{self.title} ({self.year})' # Inheritance classes (IS-A relationships) class ActionMovie(Movie): def __init__(self, title, year, director, lead_actor, budget_millions): super().__init__(title, year, director, 'Action') self.lead_actor = lead_actor self.budget_millions = budget_millions def play(self): # Override parent method return f'Now playing: {self.title}' def explosive_scene(self): return f'{self.lead_actor} performs a stunt sequence' class DocumentaryMovie(Movie): def __init__(self, title, year, director, subject, duration_minutes): super().__init__(title, year, director, 'Documentary') self.subject = subject self.duration_minutes = duration_minutes def play(self): # Override parent method return f'Now presenting: {self.title}' def get_educational_value(self): return f'Learn about {self.subject} in {self.duration_minutes} minutes' class StreamingMovie(Movie): def __init__(self, title, year, director, platform, subscription_required=True): super().__init__(title, year, director) self.platform = platform self.subscription_required = subscription_required def stream(self): if self.subscription_required: return f'Subscribe to {self.platform} to watch {self.title}' else: return f'Now streaming {self.title} on {self.platform}' # Example usage def main(): # Create Directors and Actors (for composition - HAS-A) nolan = Director('Christopher Nolan', 1970, 'British') dicaprio = Actor('Leonardo DiCaprio', 1974) hardy = Actor('Tom Hardy', 1977) spielberg = Director('Steven Spielberg', 1946, 'American') # Create different types of movies (demonstrating inheritance - IS-A) inception = ActionMovie('Inception', 2010, nolan, 'Leonardo DiCaprio', 160) inception.add_actor(dicaprio) # Movie HAS-A Actor inception.add_actor(hardy) # Movie HAS-A Actor inception.set_rating(8.8) earth_doc = DocumentaryMovie('Planet Earth', 2006, Director('David Attenborough', 1926, 'British'), 'Wildlife and Nature', 550) earth_doc.set_rating(9.4) streaming_film = StreamingMovie('The Social Dilemma', 2020, Director('Jeff Orlowski', 1981, 'American'), 'Netflix', True) streaming_film.set_rating(7.6) movies = [inception, earth_doc, streaming_film] print('> Polymorphism - Same method, different behaviors') for movie in movies: print(f' {movie.play()}') print(inception.get_info()) print(f'Action Bonus: {inception.explosive_scene()}') print(earth_doc.get_info()) print(f'Educational: {earth_doc.get_educational_value()}') print(streaming_film.get_info()) print(f'Streaming: {streaming_film.stream()}') if __name__ == '__main__': main()