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).
