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

Pygame Sprite继承结构调整后出现AttributeError: can't set attribute问题

问题:继承结构调整后出现AttributeError: can't set attribute

原本代码继承关系为HPBar→ProgressBar→pygame.sprite.Sprite,可正常运行。为扩展组件(按钮、文本框等)新增Widget类,调整为HPBar→ProgressBar→Widget→pygame.sprite.Sprite后,出现上述错误。

HPBar实例化代码

hp_bar = HPBar(
    x=x, y=y,
    entity=self.player,
    groups=[self.camera, self.extras],
)

可正常运行的修改前代码

class HPBar(ProgressBar):
    def __init__(self, entity, *args, **kwargs):
        max_value = entity.stats["max_hp"]
        value = entity.stats["hp"]
        super().__init__(
            max_value=max_value, value=value,
            width=32, height=5,
            *args, **kwargs
        )

class ProgressBar(pygame.sprite.Sprite):
    def __init__(
            self,
            x: float,
            y: float,
            width: int,
            height: int,
            groups: List[pygame.sprite.AbstractGroup] = [],
            max_value: int,
            value: int,
            *args, **kwargs
    ):
        super().__init__(groups)

    @property
    def image(self):
        _image = # pygame surface 生成逻辑
        return _image

修改后出现错误的代码

class ProgressBar(Widget):
    def __init__(
            self,
            max_value: int,
            value: int,
            *args, **kwargs
    ):
        super().__init__(*args, **kwargs)

    @property
    def image(self):
        _image = # pygame surface 生成逻辑
        return _image

class Widget(pygame.sprite.Sprite):
    def __init__(
            self,
            x: float, y: float,
            width: int, height: int,
            groups: List[pygame.sprite.AbstractGroup] = [],
    ):
        super().__init__(groups)
        self.image = pygame.Surface((width, height))

错误栈信息

File "C:\Users\Hp\Documents\Working\Personal\platformer1\game_models\windows\platformer_window.py", line 127, in load_level
    hp_bar = HPBar(
  File "C:\Users\Hp\Documents\Working\Personal\platformer1\game_models\sprites\hp_bar.py", line 16, in __init__
    super().__init__(
  File "C:\Users\Hp\Documents\Working\Personal\platformer1\contrib\models\widgets\progress_bars\progress_bar.py", line 24, in __init__
    super().__init__(*args, **kwargs)
  File "C:\Users\Hp\Documents\Working\Personal\platformer1\contrib\models\widgets\widget.py", line 22, in __init__
    self.image = pygame.Surface((width, height))
AttributeError: can't set attribute

调试尝试

在Widget类中打印width和height参数,确认数据类型正确:

super().__init__(groups)
print(width, height)
print(type(width), type(height))
self.image = pygame.Surface((width, height))

打印结果:

32 5
<class 'int'> <class 'int'>

此外,类似的Player类实现可正常运行:

class Player(pygame.sprite.Sprite):
    def __init__(self, pos):
        super().__init__()
        self.image = pygame.Surface((16, 32))

解决方案

核心原因

ProgressBar类中用@property装饰器定义了image属性,但没有配套的setter方法。当父类Widget的__init__尝试给self.image赋值时,会调用子类ProgressBar的image属性的setter,但子类未定义该方法,导致无法赋值报错。

解决方法1:给ProgressBar的image属性添加setter

class ProgressBar(Widget):
    def __init__(
            self,
            max_value: int,
            value: int,
            *args, **kwargs
    ):
        super().__init__(*args, **kwargs)

    @property
    def image(self):
        _image = # pygame surface 生成逻辑
        return _image
    
    @image.setter
    def image(self, value):
        # 可根据需求处理赋值逻辑,若无需额外操作可留空
        pass

解决方法2:调整Widget的属性命名避免冲突

修改Widget类,将基础surface存储为其他名称,避免和子类的image属性冲突:

class Widget(pygame.sprite.Sprite):
    def __init__(
            self,
            x: float, y: float,
            width: int, height: int,
            groups: List[pygame.sprite.AbstractGroup] = [],
    ):
        super().__init__(groups)
        self._base_surface = pygame.Surface((width, height))

后续ProgressBar的image属性可基于self._base_surface进行绘制逻辑处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:50:20