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:
Anker USB to USB C Cable [2 Pack, 3FT], USB A to USB C Charger Cord for Samsung Galaxy S10 S10+, LG V30, Beats Fit Pro and More (USB 2.0, Black)
$8.99 (as of February 20, 2025 12:58 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.)Elebase USB to USB C Adapter 4 Pack,USBC Female to A Male Car Charger,Type C Converter for iPhone 16 16e Pro Max,15 14 13 12 Plus,Apple Watch iWatch 10 9 8,Airpods,iPad Air Mini 6 7,Samsung Galaxy S25
$9.99 (as of February 20, 2025 12:58 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.)Amazon Basics Micro SDXC Memory Card with Full Size Adapter, A2, U3, Read Speed up to 100 MB/s, 128 GB, Black
$11.99 (as of February 20, 2025 12:58 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.