问题
I get this error during a lengthy match in my strategy game, Table Wars. It seems to occur whenever there are many units on the battlefield. Here is the traceback:
Traceback (most recent call last):
File "C:\Users\Oventoaster\Desktop\Games\Table Wars\Table Wars.py", line 727, in <module>
main()
File "C:\Users\Oventoaster\Desktop\Games\Table Wars\Table Wars.py", line 131, in main
RedTeam.update()
File "C:\Python27\lib\site-packages\pygame\sprite.py", line 399, in update
for s in self.sprites(): s.update(*args)
File "C:\Users\Oventoaster\Desktop\Games\Table Wars\Table Wars.py", line 372, in update
self.attack()
File "C:\Users\Oventoaster\Desktop\Games\Table Wars\Table Wars.py", line 393, in attack
self.target.health -= self.attack_damage
AttributeError: 'NoneType' object has no attribute 'health'
The exception seems to appear in the targeting and attacking codes, so I will post them here:
def move_toward(self, target):
if self.target is None:
self.rect.move_ip(1, 0)
def update(self):
self.find_target()
self.move_toward(self.target)
self.attack()
if self.health <= 0:
self.kill()
def find_target(self):
if self.target is not None: return
for enemy in BluTeam.sprites():
if enemy.rect.centerx - self.rect.centerx <= self.range and enemy.rect.centery - self.rect.centery <= self.range:
self.target = enemy
return
self.target = None
def attack(self):
global REDGOLD
global BLUECOMMAND
if self.target is None: return
if self.target.health <= 0:
REDGOLD += self.target.reward
BLUECOMMAND += self.target.cmdback
self.target = None
if not self.cooldown_ready(): return
self.target.health -= self.attack_damage
def cooldown_ready(self):
now = pygame.time.get_ticks()
if now - self.attack_last >= self.attack_cooldown:
self.attack_last = now
return True
return False
How do I fix this?
回答1:
Explanation of a common error or how to better understand a simple traceback to debug my program:
File "<path>\<filename>.py", line 393, in <function>
Traceback gives you the callstack and points to the error raises in which function. Nothin special here
self.target.health -= self.attack_damage
Friendly interpreter gives the statement causing the error. This is important as it means the error raised is related to this line of code.
AttributeError: 'NoneType' object has no attribute 'health'
Here we are. The error is AttributeError ; the doc is pretty clear about it: I'm trying to read the value of or I'm trying to assign to a variable that is not a member of the related object.
What is my object ? It is a 'NoneType' object
; we don't have the name, but we have its type. The object we have an issue with is NoneType
, thus it is the special object None
.
What is the error with this None
object ? It doesn't have a 'health'
attribute is saying the Traceback. So, we are accessing the attribute health
somewhere in the line of code the error raises, and this is called on a None
object.
Now we are almost all set: self.target.health
is the only location in the error line we use health
, thus it means self.target
is None
. Now I look at the source code I try to understand why it could be, even if I put a check at the beginning at the function against it. It leads to the fact I must set it to None
somehow after that line.
All of this reasoning steps lead to the short answer:
It means self.target
is None
. The error comes from your code:
if self.target.health <= 0:
REDGOLD += self.target.reward
BLUECOMMAND += self.target.cmdback
self.target = None # set to None
if not self.cooldown_ready(): return
self.target.health -= self.attack_damage # self.target is None, .health failed
来源:https://stackoverflow.com/questions/10789296/attributeerror-nonetype-object-has-no-attribute-health