You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3.10中跨类调用类实例方法报错如何解决

问题背景
  • Python版本:3.10
  • 场景:pygame开发时,尝试在Game类中调用Button类定义的is_clicked()方法实现按钮点击检测,运行时抛出如下错误:
if Button.is_clicked(event.pos):
TypeError: Button.is_clicked() missing 1 required positional argument: 'mouse_pos'
  • 目标:在Game类的event_check()事件检测逻辑中,正确调用点击检测方法,覆盖所有已创建的Button实例的点击判断。
  • 原问题代码:
import pygame, sys

class Game:
    def __init__(self, resolution: tuple, fps: int = 24):
        pygame.init()
        pygame.font.init()
        self.clock = pygame.time.Clock()
        self.resolution = resolution
        self.screen = pygame.display.set_mode(self.resolution, pygame.RESIZABLE)
        self.font = pygame.font.SysFont("Arial", 20)
        self.fps = fps

    def get_clock(self):
        return self.clock

    def get_screen(self):
        return self.screen

    def get_resolution(self):
        return self.resolution

    def get_font(self):
        return self.font

    def tick_screen(self):
        pygame.display.flip()
        self.clock.tick(self.fps)

    def event_check(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:

                # problem here :(
                if Button.is_clicked(event.pos): #REFERENCE THE BUTTON INSTANCE HERE


                    print("Button clicked!")
class Rect:
    # Constructor
    def __init__(self, x, y, width, height, color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color

    # Draw the rectangle
    def draw(self, screen):
        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))

class NarratingRect(Rect):
    # Constructor
    def __init__(self, x, y, width, height, color, font, text):
        super().__init__(x, y, width, height, color)
        self.font = font
        self.text = text

    # Draw the rectangle
    def draw(self, screen):
        super().draw(screen)
        text = self.font.render(self.text, True, (0, 0, 0))
        screen.blit(text, (self.x, self.y))

class Button(Rect):
    # Constructor
    def __init__(self, x, y, width, height, color, font, text):
        super().__init__(x, y, width, height, color)
        self.font = font
        self.text = text

    # Draw the button
    def draw(self, screen):
        super().draw(screen)
        text = self.font.render(self.text, True, (0, 0, 0))
        text_rect = text.get_rect()
        text_rect.center = (self.x + self.width // 2, self.y + self.height // 2)
        screen.blit(text, text_rect)

    # Check if the button is clicked
    def is_clicked(self, mouse_pos):
        if self.x < mouse_pos[0] < self.x + self.width and self.y < mouse_pos[1] < self.y + self.height:
            return True
        else:
            return False
错误原因

is_clicked()是Button类的实例方法,按照Python的方法调用规则:

  • 当通过具体按钮实例.is_clicked(参数)的形式调用时,Python会自动把当前按钮实例绑定给方法的第一个形参self,开发者只需要传入mouse_pos参数即可
  • 当前直接通过类名Button.is_clicked(event.pos)调用,传入的event.pos会被直接绑定给self形参,要求传入的mouse_pos没有拿到对应值,就会抛出缺参数的错误。
    除此之外,原代码没有维护所有已创建Button实例的容器,即便解决了参数传递问题,也无法实现“检测所有按钮点击”的需求。
修复方案
  • 给Game类增加实例列表,统一管理所有按钮
    在Game类的__init__方法中新增一个列表属性,专门存储所有创建好的Button实例:
def __init__(self, resolution: tuple, fps: int = 24):
    pygame.init()
    pygame.font.init()
    self.clock = pygame.time.Clock()
    self.resolution = resolution
    self.screen = pygame.display.set_mode(self.resolution, pygame.RESIZABLE)
    self.font = pygame.font.SysFont("Arial", 20)
    self.fps = fps
    # 新增:按钮实例容器
    self.buttons = []
  • 修改事件检测逻辑,遍历按钮逐个检测
    把event_check()中鼠标按下的判断逻辑改成遍历所有已注册的按钮,通过实例调用is_clicked()方法:
def event_check(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pos = event.pos
            # 遍历所有按钮检测点击
            for btn in self.buttons:
                if btn.is_clicked(mouse_pos):
                    print(f"按钮[{btn.text}]被点击")
                    # 此处编写对应按钮的点击业务逻辑即可
  • 注册按钮实例
    后续每创建一个Button实例,主动将其添加到Game实例的buttons列表中即可纳入点击检测范围,示例:
# 初始化游戏
game = Game((1280, 720))
# 创建按钮
start_btn = Button(540, 300, 200, 80, (120,220,120), game.get_font(), "开始游戏")
exit_btn = Button(540, 420, 200, 80, (220,120,120), game.get_font(), "退出游戏")
# 注册按钮到检测列表
game.buttons.append(start_btn)
game.buttons.append(exit_btn)

补充:如果硬要通过类名调用实例方法,需要手动传入按钮实例作为第一个参数,格式为Button.is_clicked(具体按钮实例, event.pos),但这种写法不符合面向对象设计习惯,也无法便捷实现多按钮遍历检测,不推荐使用。

内容的提问来源于stack exchange,提问作者Nyktein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:30:57