Search code examples
python-3.xinheritancesuper

When using the ABC module, are keyword arguments a good practice?


This question, is a followup to this one.

When using super() for multiple inheritance, the suggested approach was to use keyword arguments to pass remaining values up the call chain.

When using the ABC module, is it good practice do the same in the super().__init__ method?

The blog post, which the Python documentation about super() links to, doesn't mention anything about using **kwargs and the ABC module. It's focused on multiple inheritance with concrete classes. To rephrase my question, does the advice about using **kwargs with super() apply to classes that use the ABC module?

For example:

from abc import ABC


class GameWeapon(ABC):

    def __init__(self, name, damage, **av):
         super().__init__(**av)
         self.name = name
         self.required_strength = required_strength
         self.damage = damage


class ChargeGun(GameWeapon):

    def __init__(self, name, required_strength, damage, **av):
        super().__init__(name=name,damage=damage,**av)

Solution

  • Let's take a look at the particular instance in the blog post you refer to.

    class Shape:
        def __init__(self, shapename, **kwds):
            self.shapename = shapename
            super().__init__(**kwds)
    
    class ColoredShape(Shape):
        def __init__(self, color, **kwds):
            self.color = color
            super().__init__(**kwds)
    
    cs = ColoredShape('red', shapename='circle', radius=30)
    TypeError: object.__init__() takes no arguments
    

    When we create a ColoredShape object, it will require us to input the color and the shapename. If you pass an unexpected keyword argument, it will give you an error. This is because all classes by default (in python 3) inherit from the built-in type object, which has an __init__ that expects no arguments.

    As the article pointed out, object is guaranteed to be the last class called in the MRO. However if you remove the call to super in Shape, you can add any number of keyword arguments without issue, even though they won't be used for anything.

    class Shape:
        def __init__(self, shapename, **kwds):
            self.shapename = shapename
    
    class ColoredShape(Shape):
        def __init__(self, color, **kwds):
            self.color = color
            super().__init__(**kwds)
    
    cs = ColoredShape('red', shapename='circle', radius=30, diameter=60)
    

    In your code that you posted, you are inheriting from abc, which does not make a final call to Object's init via super. So the design pattern that is being shown in the blog post, does not apply in your case. I hope this helps.