Home > other >  Inherited __init__() function not working as intended
Inherited __init__() function not working as intended

Time:10-22

I was working on a game using the pygame library on Python. I basically defined a Character class from which the Knight class and Enemy class would inherit functions. Since both children classes use the same initialize functions, I defined the __init__() function under the parent class. However, I don't fully understand how it works and I'm getting the following error:

TypeError: __init__() takes 1 positional argument but 3 were given

Here's my code:

class Character():

    def __init__(self, img, hitbox, vel, pos_x, pos_y):
        self.img = img
        self.hitbox = hitbox
        self.vel = vel
        self.pos_x = pos_x
        self.pos_y = pos_y
    
    def draw(self):
        
        if self.right:
            pygame.transform.flip(self.img, True, False)
        
        win.blit(self.img, (self.pos_x, self.pos_y))

class Knight(Character):
    
    def __init__(self):
        Character.__init__(self)

    def move(self):
        if self.right:
            if self.x   self.vel < win_width:
                self.x  = self.vel
        if self.left:
            if self.x - self.vel > 0:
                self.x -= self.vel

main_plr = Knight("img", (19, 20), 5, 30, 20)

CodePudding user response:

As the error you are seeing says, your Knight constructor does not accept those arguments; if you are going to use that kind of inherited method extension, the class and subclass methods need to have matching argument signatures. It's also best to use super() to refer to the superclass rather than naming it explicitly.

The simplest way of handling this is to use *args and **kwargs, to concisely pass arguments that aren't needed by the subclass method to the superclass method, ie

class Character():

    def __init__(self, img, hitbox, vel, pos_x, pos_y):
        self.img = img
        self.hitbox = hitbox
        self.vel = vel
        self.pos_x = pos_x
        self.pos_y = pos_y
    

class Knight(Character):
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def move(self):
        if self.right:
            if self.x   self.vel < win_width:
                self.x  = self.vel
        if self.left:
            if self.x - self.vel > 0:
                self.x -= self.vel

CodePudding user response:

For a quick fix: just remove the __init__ method from Knight.

The error is raised because you create a Knight object with 6 arguments (self, "img", (19, 20), 5, 30, 20) whereas the __init__ method accepts only one (self).

So if your Knight objects do not have any additional attributes compared to Character objects, it will be just fine to remove the __init__ method. Now if you want your knight to have weapons, for example, you will have to do something like that:

class Knight(Character):

   def __init__(self, img, hitbox, vel, pos_x, pos_y, weapon):
      super().__init__(img, hitbox, vel, pos_x, pos_y)
      self.weapon = weapon

k = Knight("img", (19, 20), 5, 30, 20, "sword")

[Edit]

Additionaly, as suggested by @Matiiss, you can use *args to avoid repeating all arguments of Character.__init__ in Knight.__init__. One advantage, besides conciseness, is that you do not have to modify Knight if you add attributes to your Character objects.

class Knight(Character):

    def __init__(self, *args, weapon):
        super().__init__(*args)
        self.weapon = weapon

k = Knight("img", (19, 20), 5, 30, 20, weapon="sword")

But now the drawback is that you have to specify the weapon with weapon="the-weapon", since it is now a keyword argument (placed after *args).

  • Related