I have a working code with an HPBar class --> inherits from ProgressBar class --> inherits from pygame.sprite.Sprite. I decided to create a Widget class to have the following inheritance flow: HPBar --> ProgressBar --> Widget --> pygame.sprite.Sprite. The point in doing so is for flexibility especially when adding more widgets like buttons, textboxes, etc. However, in my revision I encountered Attribute error: can't set attribute
. Details are as follows.
Somewhere in my code I have this HPBar
instantiation:
hp_bar = HPBar(
x=x, y=y,
entity=self.player,
groups=[self.camera, self.extras],
)
Working Code: This worked prior to the revision.
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
Revised Code: The code with the Attribute error.
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))
Traceback Error:
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
Few debugging attempts:
I tried to print out the width
and height
arguments inside the Widget
class to make sure I'm receiving and sending the correct data type:
In Widget class:
super().__init__(groups)
print(width, height)
print(type(width), type(height))
self.image = pygame.Surface((width, height))
Print result:
32 5
<class 'int'> <class 'int'>
Moreover, I have had this implementation resembling my Widget class implementation and this works fine:
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((16, 32))
Edit:
I got the code working by omitting the self.image
attribute in Widget
class. I'm assuming it's because of the image
property in ProgressBar
. However, I still don't fully understand why. Hopefully someone can explain.
class Widget(pygame.sprite.Sprite):
def __init__(
self,
x: float, y: float,
width: int, height: int,
groups: List[pygame.sprite.AbstractGroup] = [],
):
super().__init__(groups)
CodePudding user response:
Yes, of course. You can't have a method/property and an attribute with the same name. image
can be either an attribute or a property. But you can't have 2 objects with the same name.
The following is not possible:
class Foo:
def __init__(self):
self.bar = 1
def bar(self):
return 2
print(Foo().bar())
print(Foo().bar()) TypeError: 'int' object is not callable
Also not possible:
class Foo:
def __init__(self):
self.bar = 1
@property
def bar(self):
return 2
print(Foo().bar)
self.bar = 1 AttributeError: can't set attribute 'bar'
However you can define a setter:
class Foo:
def __init__(self):
self._bar = 1
self.bar = 2
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, value):
self._bar = value
print(Foo().bar)
2