2

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)
  • What do you mean by "appropriate?" Do you have some measurable notion of "appropriateness?" – Robert Harvey Feb 17 '19 at 16:26
  • @RobertHarvey - I mean correct or good practice in relation to the advice given in the blog and in the previous answer. –  Feb 17 '19 at 16:27
  • That's just re-stating "appropriate." What is your *criteria* for being appropriate? – Robert Harvey Feb 17 '19 at 16:28
  • On your previous question, the answer you put the checkmark next to starts with the sentence *"super() requires your code cooperates. Your Weapon and Reloadable classes don't, so you actually don't want to use super() here."* **That is actionable advice.** Simply stating that something is "appropriate" or "best practice" is not actionable *without stating why.* Conversely, it's difficult to answer your question without knowing the *why* you are after. – Robert Harvey Feb 17 '19 at 16:32
  • I'd say there's _no need to_ use keyword arguments in your code because you can simply do `super().__init__(name, damage,**av)`. That's also more readable, to my mind. – ForceBru Feb 17 '19 at 16:32
  • @RobertHarvey - Every example I've seen with the `ABC` module, never used `**kwargs`, I just read the blog post and I was wondering if the advice in both the previous answer and the blog post applies to inheritance with concrete classes or concrete and base classes. –  Feb 17 '19 at 16:35
  • @RobertHarvey - I was just wondering if the `ABC` module changes the advice given in the blog and previous answer. –  Feb 17 '19 at 16:38
  • What do you think? – Robert Harvey Feb 17 '19 at 16:40
  • @RobertHarvey - I don't know enough to give a definitive answer. I complied the code and it works, but as far as what is going on underneath when I use the `ABC` module and `**kwargs`, I can't say for sure. Does the `ABC` module change things? The blog post didn't mention `ABC` modules or abstract classes. The author was focused on multiple inheritance with concrete classes. Does the advice apply to classes that use the `ABC` module as well? That's my question. –  Feb 17 '19 at 16:43
  • Include that information in your post. – Robert Harvey Feb 17 '19 at 16:46

1 Answers1

0

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.

Chad
  • 118
  • 8
  • So, in other words, no need for `kwargs` in the `super()`? Correct? I just pass in what the base constructor needs and leave it. –  Feb 18 '19 at 05:10
  • 1
    @EmilyScott: but take into account that using classes a base classes at different levels of a class inheritance hierarchy can lead to a MRO that puts what you think of as the last class somewhere earlier. You won't usually build such hierarchies but [it does have its uses](https://stackoverflow.com/a/53085935/100297). *If* your classes are to be used as mix-in classes, then you need to account for this by calling `super()`, and in a `__init__` callchain, using `**kwargs` is a great way of passing on remaining arguments. – Martijn Pieters Feb 18 '19 at 11:30
  • I agree with everything Martijn Pieters pointed out. Passing `**kwargs` up the call chain can reduce the need to have a very lengthy `__init__` that might need, say, 20 arguments. – Chad Feb 18 '19 at 12:24
  • @MartijnPieters - *using classes a base classes at different levels of a class inheritance hierarchy*, you mean when you use an abstract class, but that class isn't the top of the inheritance hierarchy, correct? For example, and abstract class inherits another abstract class? –  Feb 18 '19 at 13:49
  • 1
    @EmilyScott: yes, or when you use a class that inherits from an ABC as a mixin class in a larger hierarchy. Play with mixin classes and look at the `__mro__` attribute to see the linear order they have been put in. – Martijn Pieters Feb 18 '19 at 13:54