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

如何修复Python/Pygame类中的AttributeError并验证类属性

Pygame中monitor类的AttributeError修复及相关问题解答

我编写的Python/Pygame程序旨在运行时显示嵌套的彩色显示器,但始终出现报错:AttributeError: type object 'monitor' has no attribute 'x',不确定是否是类中的classmethod导致问题。

原代码

import pygame
import os
import math 

clock = pygame.time.Clock()

class monitor(object):
    def __init__(self, x, y, color, length, width, offset, offsetcolor):
            self.x = x
            self.y = y
            self.color = color
            self.color =(100,100,100)
            self.length = length
            self.width = width
            self.offset = offset
            self.offsetcolor = offsetcolor
                
    @classmethod  
    def draw(cls, win):
        #attribute checker
        if hasattr(cls, m.x):
                print("Monitor's X attribute is ", {cls.x})
            
            else:
                print("Monitor's x feature is not working...")
        
                #monitor drawing
        border = pygame.Rect(cls.x, cls.y, cls.width, cls.length)
            oborder = pygame.Rect(cls.x + cls.offset, cls.y + cls.offset, cls.width - (10* cls.offset), cls.length - (10* cls.offset))
        pygame.draw.rect(win, cls.color, border)
        pygame.draw.rect(win, cls.offsetcolor, oborder)
        print(cls.color + ' ' +cls.offsetcolor)
        my_monitor = monitor(10, 10, (255, 0, 0), 100, 50, 5, (0, 255, 0))
        my_monitor.draw(win)
        pygame.display.update()

        def redrawGameWindow():
                monitor.draw(win)

#mainloop & variables 
m = monitor(100,100,(100,100,100), 800, 1000, 2, (150,150,150))
m.x = 100
m.y = 100
m.width = 1000
m.length = 800
m.offset = 2

while run:
    clock.tick(27)
        
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
            pygame.quit()
        
    keys = pygame.key.get_pressed()

    if keys[pygame.K_ESCAPE]:
    run = False
    pygame.quit()
        
    #if keys[pygame.K_SPACE]:
    redrawGameWindow()           
  
pygame.quit()

报错信息

Traceback (most recent call last):
  File "Monitor.py", line 115, in <module>
    redrawGameWindow()           
  File "Monitor.py", line 70, in redrawGameWindow
    monitor.draw(win)
  File "Monitor.py", line 45, in draw
    border = pygame.Rect(cls.x, cls.y, cls.width, cls.length)
AttributeError: type object 'monitor' has no attribute 'x'

我尝试过调整属性顺序、在主循环传递变量、打印属性值,但都无效。想请教:

  1. 如何修复该AttributeError?
  2. 类方法是否需要不同的属性继承方式?
  3. 主循环中的变量是否冗余?
  4. 如何验证类属性是否存储了预期值?
  5. 后续如何排查这类错误?

问题解答

1. 修复AttributeError的核心方案

错误根源是误用类方法(classmethod):类方法的cls参数指向类本身,而非实例对象,而x、y是实例属性,只有实例才拥有。具体修复步骤:

  • 移除@classmethod装饰器,将draw改为实例方法,参数从cls替换为self
  • 把方法内所有cls.xxx改为self.xxx
  • 删除draw方法内部创建my_monitor并调用draw的递归代码(会导致无限循环)
  • 修正hasattr的错误用法:hasattr(self, 'x')才是检查实例属性的正确方式
  • 修复代码缩进混乱问题,补充缺失的窗口初始化、run变量定义
  • 修正偏移量计算逻辑(原代码10*cls.offset会导致矩形尺寸为负)

修正后的关键代码片段:

class monitor(object):
    def __init__(self, x, y, color, length, width, offset, offsetcolor):
        self.x = x
        self.y = y
        self.color = color  # 移除硬写的color赋值,保留传入参数的作用
        self.length = length
        self.width = width
        self.offset = offset
        self.offsetcolor = offsetcolor
            
    def draw(self, win):
        # 属性检查
        if hasattr(self, 'x'):
            print(f"Monitor's X attribute is {self.x}")
        else:
            print("Monitor's x feature is not working...")
        
        # 绘制显示器
        border = pygame.Rect(self.x, self.y, self.width, self.length)
        oborder = pygame.Rect(self.x + self.offset, self.y + self.offset, self.width - (2*self.offset), self.length - (2*self.offset))
        pygame.draw.rect(win, self.color, border)
        pygame.draw.rect(win, self.offsetcolor, oborder)
        print(f"{self.color} {self.offsetcolor}")

def redrawGameWindow(win, m):
    win.fill((0,0,0))  # 填充背景避免画面重叠
    m.draw(win)
    pygame.display.update()

# 补充初始化代码
pygame.init()
win = pygame.display.set_mode((1200, 900))
run = True

#mainloop & variables 
m = monitor(100,100,(100,100,100), 800, 1000, 2, (150,150,150))

while run:
    clock.tick(27)
        
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        
    keys = pygame.key.get_pressed()

    if keys[pygame.K_ESCAPE]:
        run = False
        
    redrawGameWindow(win, m)           
  
pygame.quit()

2. 类方法的属性使用规则

类方法(@classmethod装饰)属于类本身,cls参数代表类,只能访问类属性(定义在类内部、方法外部的属性,比如class monitor: count = 0),无法直接访问实例属性。

如果要操作具体实例的属性,必须用实例方法(不带装饰器,第一个参数为self,指向当前实例)。你这里的draw是绘制单个显示器实例,完全不适合用类方法。

3. 主循环中的变量是否冗余

主循环前的这段代码是冗余的:

m.x = 100
m.y = 100
m.width = 1000
m.length = 800
m.offset = 2

因为创建m时已经传入了这些参数,重复赋值没有意义,除非你需要覆盖初始化值,否则可以直接删除。

4. 验证类/实例属性的预期值

  • 验证实例属性:直接打印实例属性(如print(m.x, m.color)),或在__init__末尾添加print(self.__dict__),查看所有实例属性的键值对
  • 验证类属性:直接打印类属性(如print(monitor.count)),或print(monitor.__dict__)查看类的所有属性
  • 在方法内部添加打印语句,比如在draw中打印self.x、self.width,确认值是否符合预期

5. 这类错误的排查步骤

  1. 定位错误行:根据报错信息中的行号,直接检查对应代码的变量来源
  2. 区分类与实例:明确cls指向类,self指向实例,类属性和实例属性的存储位置不同
  3. 检查属性定义:确认属性是类层面(类内方法外)还是实例层面(self.xxx)的定义
  4. 打印调试:在报错行前打印dir(cls)或dir(self),查看类/实例的所有可用属性;打印变量值确认是否正确
  5. 检查装饰器:如果用了@classmethod或@staticmethod,确认是否符合使用场景——类方法用于操作类属性,静态方法无需访问类/实例属性,实例方法用于操作实例属性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:10:56