I’ve spent a lot of time refining my Python code, and one technique that has greatly improved my projects is the use of the built-in super() function. In my early days, I used to hardcode parent class names when calling inherited methods. Over time, I realized that super() not only simplifies the code but also makes it more robust—especially when dealing with inheritance and multiple parent classes.
Thank me by sharing on Twitter 🙏
1. Understanding the Basics of super()
To begin with, super() allows me to access methods from a parent or sibling class without explicitly naming them. This approach is invaluable when I need to extend or modify functionality. For instance, if I override a method in a subclass, I can still call the original method from the parent class, thereby reducing redundancy. Consider this simple example:
class Parent:
def __init__(self):
print("Parent initializer")
class Child(Parent):
def __init__(self):
super().__init__() # Calls Parent.__init__()
print("Child initializer")
In this example, using super().init() ensures that the Parent initializer runs, setting the stage for any additional logic in the Child initializer.
2. Using super() in Python 3
In my everyday Python 3 coding, I always opt for the zero-argument version of super(). This style is concise and less prone to mistakes. For instance, initializing a child class is as simple as:
class Child(Parent):
def __init__(self):
super().__init__()
print("Child initializer")
Passing Arguments from Child to Parent
Occasionally, I need to pass arguments to the parent class from the child class. This scenario is common when the parent class requires specific initialization parameters, and the child class either adds new ones or reuses them. For example, suppose I have a parent class that requires a name:
HP 63 Black/Tri-color Ink Cartridge (2-pack) | Works with HP DeskJet 1112, 2130, 3630 Series; HP ENVY 4510, 4520 Series; HP OfficeJet 3830, 4650, 5200 Series | Eligible for Instant Ink | L0R46AN
$56.89 (as of February 21, 2025 12:59 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Logitech C920x HD Pro Webcam, Full HD 1080p/30fps Video Calling, Clear Stereo Audio, HD Light Correction, Works with Skype, Zoom, FaceTime, Hangouts, PC/Mac/Laptop/Macbook/Tablet - Black
$49.99 (as of February 21, 2025 12:59 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)The Nvidia Way: Jensen Huang and the Making of a Tech Giant
$17.50 (as of February 21, 2025 12:59 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)class Parent:
def __init__(self, name):
self.name = name
print(f"Parent initializer with name: {self.name}")
Then, in my child class, I can pass arguments to the parent class like this:
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # Pass name to Parent.__init__()
self.age = age
print(f"Child initializer with age: {self.age}")
In this case, when I create an instance of Child, I provide both a name and an age:
child = Child("Alex", 10)
The output is as follows:
Parent initializer with name: Alex
Child initializer with age: 10
By passing arguments to the parent class via super(), I ensure that the Parent class is properly initialized while also extending its functionality with additional attributes in the Child class.
3. When to Use super() with Arguments
While the zero-argument form is my go-to in Python 3, there are times when I work with legacy Python 2 code. In those cases, I have to use super() with explicit arguments. For example:
class Child(Parent):
def __init__(self, name, age):
super(Child, self).__init__(name)
self.age = age
print(f"Child initializer with age: {self.age}")
This syntax is necessary for compatibility with older versions, but I try to avoid it whenever possible in modern Python code.
4. Avoiding Common Pitfalls
One mistake I made early on was attempting to pass self directly to super(), like so:
class Child(Parent):
def __init__(self):
super(self).__init__() # Incorrect usage
This approach is wrong because super() does not expect self as its sole argument. By adhering to the correct usage—either the zero-argument form for Python 3 or the explicit version for legacy support—I maintain cleaner and more reliable code.
In conclusion, my journey with super() has led me to write more maintainable and robust Python programs. Whether I’m simply calling a parent method or passing initialization arguments between classes, understanding the nuances of super() helps me manage inheritance effectively and reduce code redundancy.