Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'Unexpected Keyword Argument' in super().__init__()

I'm writing a small text game. I keep getting an error when trying to define a class variable.

Here's the class code:

class Scenery():
    def __init__(self,name,description):
        self.name=name
        self.description=description

class Door(Scenery):
    def __init__(self,openstatus,lockstatus):
        self.openstatus=openstatus
        self.lockstatus=lockstatus
        super().__init__(name,description,openstatus,lockstatus)

class CageDoor(Door):
    def __init__(self):
        super().__init__(lockstatus=False,
                         openstatus=False,
                         name="Cage Door",
                         description="It's the door to the cage.")

The main.py code:

from tiles import CageDoor

CageDoor = CageDoor()

And the error:

  File "main.py", line 3, in <module>
    CageDoor = CageDoor()
  *File Location*
    name="Cage Door"
TypeError: __init__() got an unexpected keyword argument 'name'
like image 274
ContortedTrash Avatar asked Dec 16 '15 23:12

ContortedTrash


2 Answers

When using super it is important that all the methods in the call chain use the same interface. Here you have Door not taking name, or description. And Scenery doesn't take openstatus or lockstatus. You should have every method in the call chain accept *args, and **kwargs so it can ignore parameters it doesn't care about. For more information see this post

In this example it means re-writing Door and Scenery thusly:

class Scenery():
    def __init__(self,name,description, *args, **kwargs):
        self.name=name
        self.description=description

class Door(Scenery):
    def __init__(self openstatus,lockstatus, *args, **kwargs):
        self.openstatus=openstatus
        self.lockstatus=lockstatus
        super().__init__(*args, **kwargs)
like image 61
Chad S. Avatar answered Oct 03 '22 06:10

Chad S.


Door's __init__ doesn't accept name or description, so the call in CageDoor.__init__ (which passes control to Door.__init__ because super() determines that is the next class up in the inheritance hierarchy) is going to fail.

Change Door.__init__ to:

class Door(Scenery):
    def __init__(self,openstatus,lockstatus, *args, **kwargs):
        self.openstatus=openstatus
        self.lockstatus=lockstatus
        super().__init__(*args, **kwargs)

and it will then seamlessly pass along all arguments besides the two it uses to the next __init__ up the chain. The advantage to accepting and passing *args and **kwargs is that even if Scenery's constructor prototype changes, Door doesn't have to; the callers would need to pass along the correct arguments if no defaults are provided (so adding new arguments to Scenery's constructor without giving them useful defaults is poor form), but Door remains stable.

like image 42
ShadowRanger Avatar answered Oct 03 '22 08:10

ShadowRanger