如何修复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'
我尝试过调整属性顺序、在主循环传递变量、打印属性值,但都无效。想请教:
- 如何修复该AttributeError?
- 类方法是否需要不同的属性继承方式?
- 主循环中的变量是否冗余?
- 如何验证类属性是否存储了预期值?
- 后续如何排查这类错误?
问题解答
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. 这类错误的排查步骤
- 定位错误行:根据报错信息中的行号,直接检查对应代码的变量来源
- 区分类与实例:明确
cls指向类,self指向实例,类属性和实例属性的存储位置不同 - 检查属性定义:确认属性是类层面(类内方法外)还是实例层面(
self.xxx)的定义 - 打印调试:在报错行前打印
dir(cls)或dir(self),查看类/实例的所有可用属性;打印变量值确认是否正确 - 检查装饰器:如果用了
@classmethod或@staticmethod,确认是否符合使用场景——类方法用于操作类属性,静态方法无需访问类/实例属性,实例方法用于操作实例属性
内容的提问来源于stack exchange,提问作者TechDude
相关产品推荐
相关产品推荐

