Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python **kwargs in parent and child constructor

If I write an inheritance relationship as follows:

class Pet(object):
  def __init__(self, n):
    print n

class Dog(Pet):
  def __init__(self, **kwargs):
    Pet.__init__(self, 5)

Then the output is 5. If, however, I wanted to do:

class Pet(object):
  def __init__(self, **kwargs):
    if not "n" in kwargs:
      raise ValueError("Please specify the number I am to print")
    print kwargs["n"]

class Dog(Pet):
  def __init__(self, **kwargs):
    Pet.__init__(self, kwargs)

Then I get the error TypeError: __init__() takes exactly one argument (two given)

How can I pass the extra arguments up the inheritance chain in this way?

like image 548
Andrew Latham Avatar asked Aug 05 '14 03:08

Andrew Latham


2 Answers

Simply pass the arguments down as keyword arguments:

class Pet(object):
  def __init__(self, **kwargs):
    if not "n" in kwargs:
      raise ValueError("Please specify the number I am to print")
    print kwargs["n"]

class Dog(Pet):
  def __init__(self, **kwargs):
    Pet.__init__(self, **kwargs)

However, you should use super rather than hardcoding the superclass.

Change your definition of Dog to (Python 2.X):

class Dog(Pet):
  def __init__(self, **kwargs):
    super(Dog, self).__init__(**kwargs)

And in Python 3.X it's nicer, just:

class Dog(Pet):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
like image 137
stderr Avatar answered Oct 12 '22 23:10

stderr


Figured it out: Use Pet.__init__(self, **kwargs)

It's called "unpacking" and it transforms the dictionary kwargs into a list of argument=value pairs.

Then **kwargs in the parent constructor is able to handle them. Just passing a dictionary would not work because **kwargs in the constructor is expecting a bunch of argument=value pairs but instead I was just passing it one value, the dictionary kwargs from the child.

like image 23
Andrew Latham Avatar answered Oct 12 '22 23:10

Andrew Latham