Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
119: Inheritance and the super() Function
I once worked with a developer who spent three days tracking down a bug that only existed in one of twelve different payment processing classes. He had built a Payment class, and then created CreditCardPayment, PayPalPayment, ApplePayPayment, and so on. Instead of using inheritance properly, he had copy-pasted the core logic—things like transaction IDs and timestamping—into every single subclass. When a requirement changed regarding how we formatted transaction IDs, he updated the base class, but forgot about four of the subclasses. It was a nightmare to debug because the behavior was subtly inconsistent across the app.
That is exactly the kind of mess inheritance is designed to prevent. At its core, inheritance lets you define a "base" class with all the common behavior and then create "derived" classes that inherit those traits while adding their own specific twists. You aren't just saving keystrokes; you're creating a single source of truth for your logic.
Stopping the Copy-Paste Cycle with Inheritance
When you create a child class, you pass the parent class as an argument in the class definition. From that moment on, the child class has access to every method and attribute of the parent. You don't have to redefine the things that are universal to all objects of that type.
class Payment:
def __init__(self, amount, currency):
self.amount = amount
self.currency = currency
print(f"Processing {self.amount} {self.currency}...")
def generate_receipt(self):
print(f"Receipt created for {self.amount} {self.currency}")
class CreditCardPayment(Payment):
def authorize_card(self):
print("Checking credit limit and CVV...")
# CreditCardPayment now has access to generate_receipt()
# even though we didn't define it inside the child class.
cc_pay = CreditCardPayment(100, "USD")
cc_pay.generate_receipt()
In this example, CreditCardPayment is the child. It gets everything Payment has for free, but it also gets its own specialized method, authorize_card(). This keeps your code clean and ensures that if you ever need to change how generate_receipt works, you only have to change it in one place.
Using super() to Avoid Redundant Setup
Now, here is where things usually get tricky for people. What happens if your child class needs its own __init__ method to handle extra data? If you define __init__ in the child class, it completely overrides the parent's __init__. You'll find that your amount and currency attributes suddenly vanish because the parent's setup code never ran.
This is why we use the super() function. It tells Python, "Go back to the parent class and run this method first, then come back here and finish what I'm doing." It's essentially a way to extend the parent's behavior rather than replacing it entirely. I've seen far too many developers try to call the parent class by name (like Payment.__init__(self, ...)), but super() is the professional standard because it handles complex inheritance hierarchies much more gracefully.
class CreditCardPayment(Payment):
def __init__(self, amount, currency, card_number):
# We call the parent's __init__ to handle amount and currency
super().__init__(amount, currency)
# Now we handle the part specific to credit cards
self.card_number = card_number
print(f"Card {self.card_number} linked to transaction.")
cc_pay = CreditCardPayment(150, "EUR", "4111-XXXX-XXXX-1111")
# Because of super(), we still have access to the amount attribute
print(f"Total: {cc_pay.amount}")
Without that super().__init__(amount, currency) call, cc_pay.amount would throw an AttributeError. You're essentially layering your logic: the base class handles the "what is a payment?" part, and the child class handles the "what makes this a credit card payment?" part.
📋 Practical Task
Building a Specialized Vehicle Fleet Management System
You are building a system to track a company's vehicle fleet. You need to ensure that all vehicles share some basic traits, but different types of vehicles have different requirements.
- Create a base class called
Vehicle. Its__init__method should accept and assignmakeandmodel. It should also have a method calledget_descriptionthat returns a string like "This is a [make] [model]". - Create a derived class called
ElectricVehicle. This class should inherit fromVehicle. - The
ElectricVehicleclass needs its own__init__method that acceptsmake,model, andbattery_capacity. Usesuper()to handle the make and model, and assign the battery capacity locally. - Override the
get_descriptionmethod inElectricVehicleso that it returns the original description from the parent class PLUS the battery capacity (e.g., "This is a Tesla Model 3 with a 75kWh battery"). Usesuper().get_description()inside this method to avoid rewriting the string logic.
Test your code by: Creating an instance of ElectricVehicle and printing the result of get_description().
There are no comments for now.