Home > Mobile >  Python inheriting generic type: TypeError: object.__init__() takes exactly one argument
Python inheriting generic type: TypeError: object.__init__() takes exactly one argument

Time:06-22

I am trying to make a class Sprite that inherits generic class T, with the bound of being a subclass of class Object. Class Text is a subclass of class Object. This is class Text, provided by outer library:

# text.py
class Text(Object):
    # ignored properties...
    def __init__(self, text="placeholder text", **kwargs):
        super().__init__(object_type=Text.object_type, text=text, **kwargs)

This is my self-written class Sprite:

# sprite.py
from typing import TypeVar, Generic

T = TypeVar('T', bound=Object)

class Sprite(Generic[T]):
  def __init__(self, **kwargs):
    super(Sprite, self).__init__(self, clickable=True, evt_handler=self.click_wrapper, **kwargs)

And such a Sprite instance is initialized by:

  sprite = Sprite[Text](
    text="This is a sprite!",
    object_id="spriteTest",
    # other similar arguments...
  ) 

And this is the error thrown:

Exception thrown in main()! Terminating main...
Traceback (most recent call last):
  File "sprite.py", line 79, in main
    sprite = Sprite[Text](
  File "C:\ProgramData\Anaconda3\lib\typing.py", line 687, in __call__
    result = self.__origin__(*args, **kwargs)
  File "sprite.py", line 47, in __init__
    super(Sprite, self).__init__(self, clickable=True, evt_handler=self.click_wrapper, **kwargs)
TypeError: object.__init__() takes exactly one argument (the instance to initialize)

Why is this not working?

CodePudding user response:

I believe you are misunderstanding Generic Type variables here. Let me first try to reduce your bug down to its most minimal variant:

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

Sprite(text="My text")

This very simple program throws the exact same Exception as you have:

Traceback (most recent call last):
  File ".../72690805.py", line 57, in <module>
    Sprite(text="My text")
  File ".../72690805.py", line 55, in __init__
    super().__init__(**kwargs)
TypeError: object.__init__() takes exactly one argument (the instance to initialize)

The key here is that it is object for who you cannot specify anything other than one argument. With other words, the superclass of Sprite is object in both of our cases (i.e. the default Python object, not your Object class). Your Sprite class simply does not have a non-default superclass.

You seem to be of the understanding that your super(...).__init__(...) call will initialize Text whenever you use Sprite[Text](...), but that is not the case. Let me give a common example of a Generic type variable in use:

from typing import List, TypeVar, Generic

T = TypeVar('T')

class Queue(Generic[T]):

    def __init__(self) -> None:
        super().__init__()
        self.queue: List[T] = []

    def put(self, task: T) -> None:
        self.queue.append(task)

    def get(self) -> T:
        return self.queue.pop(-1)

queue = Queue()
queue.put(12)
queue.put(24)
queue.put(36)
# queue.put('a') # <- A type checker should disallow this
print(queue.get())
print(queue.get())
print(queue.get())

Here, we have a simple Queue class, with put and get methods. These functions are supplemented with Type hints via T, and now type checkers know that e.g. Queue[int]().get returns an int. However, the super().__init__() is still just the standard initialization of the Python object. We're not suddenly initializing an int, which is equivalent to what you seem to be trying.

To wrap up; whenever you find yourself using functionality from the typing module to try and get something working, then you're making a mistake. As far as I'm aware, all the functionality from typing is merely "cosmetic", and is ignored by Python. It exists to allow developers to use type checkers to ensure that they are not making mistakes, e.g. calling queue.put('a') when queue was initialized with Queue[int](). To reiterate, this put of a character will still execute in Python, and it will place the character in the queue, even though a Type checker would tell you that it's wrong.

  • Related