【问题标题】:Inherited __init__() function not working as intended继承的 __init__() 函数未按预期工作
【发布时间】:2021-10-21 14:49:55
【问题描述】:

我正在使用 Python 上的 pygame 库开发游戏。我基本上定义了一个Character 类,Knight 类和Enemy 类将继承函数。由于两个子类使用相同的初始化函数,我在父类下定义了__init__() 函数。但是,我不完全理解它是如何工作的,并且出现以下错误:

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

这是我的代码:

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)

【问题讨论】:

标签: python oop inheritance


【解决方案1】:

为了快速解决:只需从 Knight 中删除 __init__ 方法。

引发错误是因为您创建了一个带有 6 的 Knight 对象 参数 (self, "img", (19, 20), 5, 30, 20) 而__init__ 方法只接受一个 (self)。

因此,如果您的 Knight 对象没有任何附加属性 与Character 对象相比,删除 __init__ 方法。现在如果你想让你的骑士有武器,因为 例如,您将不得不这样做:

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

[编辑]

另外,正如@Matiiss 所建议的,您可以使用*args 来避免 在Knight.__init__ 中重复Character.__init__ 的所有参数。 除了简洁之外,一个优点是您不必修改 Knight 如果您将属性添加到您的 Character 对象。

class Knight(Character):

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

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

但现在的缺点是你必须指定weapon weapon="the-weapon",因为它现在是一个关键字参数(放置 在*args) 之后。

【讨论】:

  • 另外为了缩短你可以使用def __init__(self, *args, weapon)然后super().__init__(*args)的代码,但是它必须像这样实例化:k = Knight('img', (19, 20), 5, 30, 20, weapon='sword')
  • @Matiiss 非常感谢您的建议。我将其包含在我的答案中。
  • 哦,实际上你可以这样做:def __init__(self, *args): 然后super().__init__(args[:-1])(或args[:5] 可能更好)然后self.weapon = args[-1](或args[5]),然后它会是一个位置参数(虽然不如应该的那样明确(基本上可能,但明确性更好,所以不建议使用它))
  • @Matiiss args[:5]args[5] 恕我直言,因为这样您就失去了一个主要优势,即您可以修改 Character.__init__ 签名而无需修改 Knight.__init__
  • 是的,而且可能更难理解参数代表什么
【解决方案2】:

正如您看到的错误所说,您的 Knight 构造函数不接受这些参数;如果您要使用这种继承的方法扩展,则类和子类方法需要具有匹配的参数签名。最好使用super() 来引用超类,而不是显式命名它。

最简单的处理方法是使用*args**kwargs,将子类方法不需要的参数简洁地传递给超类方法,即

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-15
    • 1970-01-01
    • 2016-10-18
    • 2018-02-01
    • 1970-01-01
    • 2019-10-30
    • 2015-04-11
    相关资源
    最近更新 更多