Hello python gurus! I dabble in python casually, and I've just recently begun to use classes. For the most part they've proven very helpful, but this error has me stumped:
creature.health=creature.health-2*creature.metabolsim/resolution
AttributeError: predator instance has no attribute 'metabolsim'
Here's the full code of the program (it's designed to run a very simplistic simulation of evolution in an ecosystem), still riddled with errors, most likely.
The blocks pertinent to this issue are:
line 125 where the function is called,
the function itself starting on line 101,
and the definition of the class Predator, beginning line 62.
(I know it runs a little long, I'll clean it up with more functions once I get it running as is):
import random
import math
### DEFINING CLASSES ###
#starting plants will be generated from prototypes
class Protoplant:
def __init__(self):
self.Coord=[random.randrange(0,100),random.randrange(0,100)]
self.health=random.randrange(50,100)
self.split=random.randrange(150,200)
self.plasticity=random.randrange(0,20)
class Protoprey:
def __init__(self):
self.Coord=[random.randrange(0,100),random.randrange(0,100)]
self.health=random.randrange(400,500)
self.split=self.health*2
self.metabolism=random.randrange(2,5)
self.paranoia=random.gauss(1.0,0.5)
self.plasticity=random.randrange(0,20)
class Protopredator:
def __init__(self):
self.Coord=[random.randrange(0,100),random.randrange(0,100)]
self.health=random.randrange(800,1000)
self.split=self.health*2
self.metabolism=random.randrange(3,6)
self.plasticity=random.randrange(0,20)
def MAKE_ATTRIBUTES(child,parent,Attributes,Morph):
child.Coord=[parent.Coord(0)+random.gauss(0,5),parent.coord(1)+random.gauss(0,5)]
child.plasticity=parent.plasticity+random.randrange(-5,5)
for attribute in Attributes:
child.attribute=parent.attribute+random.gauss(0,Morph[Attributes.index(attribute)])*parent.plasticity
class Plant:
def __init__(self, parent):
# MAKE_ATTRIBUTES(self,parent,['health','split'],[1,1])
self.Coord=[parent.Coord[0]+random.gauss(0,5),parent.Coord[1]+random.gauss(0,5)]
self.health=parent.health+random.gauss(0,parent.plasticity)
self.split=parent.split+random.gauss(0,parent.plasticity)
self.plasticity=parent.plasticity+random.randrange(-5,5)
def DEATH(self):
if random.randrange(0,int(self.health*resolution)*10)==0:
Plants.remove(self)
class Prey:
def __init__(self,parent):
self.Coord=[parent.Coord[0]+random.gauss(0,5),parent.Coord[1]+random.gauss(0,5)]
self.health=parent.health+random.gauss(0,parent.plasticity)
self.split=parent.split+random.gauss(0,parent.plasticity)
self.metabolism=parent.metabolism+random.gauss(0,0.05*parent.plasticity)
self.paranoia=parent.paranoia+random.gauss(0,0.05*parent.plasticity)
self.plasticity=parent.plasticity+random.randrange(-5,5)
def ACT(self):
if SEEK(self,Plants,2)<SEEK(self,Predators,2)*self.paranoia:
CHASE(self,SEEK(self,Plants,1),Plants)
else:
FLEE(self,SEEK(self,Predators,1))
class Predator:
def __init__(self,parent):
self.Coord=[parent.Coord[0]+random.gauss(0,5),parent.Coord[1]+random.gauss(0,5)]
self.health=parent.health+random.gauss(0,parent.plasticity)
self.split=parent.split+random.gauss(0,parent.plasticity)
self.metabolism=parent.metabolism+random.gauss(0,0.05*parent.plasticity)
self.plasticity=parent.plasticity+random.randrange(-5,5)
### DEFINING FUNCTIONS ###
def CHASE(mover,point,Point_Family): #moves an object (mover) towards another object (point)
mag=math.sqrt((point.Coord[0]-mover.Coord[0])**2+(point.Coord[1]-mover.Coord[1])**2)#calculates the distance between the objects
if mag < 3*(mover.metabolism/resolution): # If the mover is very close to the predator
mover.health=mover.health+point.health #cause mover to absorb point's health
Point_Family.remove(point) #then remove the point
else:
for c in range (0,2):
mover.Coord[c]=mover.Coord[c]+(point.Coord[c]-mover.Coord[c])*mover.metabolism/(mag*resolution) #moves mover towards point
def FLEE(mover,point): #moves an object (mover) away from another object (point)
mag=math.sqrt((point.Coord[0]-mover.Coord[0])**2+(point.Coord[1]-mover.Coord[1])**2)#calculates the distance between the objects
for c in range (0,2):
mover.Coord[c]=mover.Coord[c]-(point.Coord[c]-mover.Coord[c])*mover.metabolism/(mag*resolution) #moves mover away from point
def SEEK(mover,Point_Family,output):
Magnitudes=[]#A list of the distances from each point to the mover
for point in Point_Family:
Magnitudes.append(math.sqrt((point.Coord[0]-mover.Coord[0])**2+(point.Coord[1]-mover.Coord[1])**2))#calculates the distance to a point
if output==1:
return(Point_Family[Magnitudes.index(min(Magnitudes))])#returns the point that corresponds to the least value in Magnitudes
else:
return(min(Magnitudes))
def SPLIT(splitter,Family,Class):
if splitter.health > splitter.split:
print('a', splitter ,'is born!' )
splitter.health=int(splitter.health/2)
Family.append(Class(splitter))
def DEPLETE (creature):
creature.health=creature.health-2*creature.metabolsim/resolution
###INTRODUCING OBJECTS###
cycles=1000.0
resolution=100
Plants=[]
Preys=[]
Predators=[]
#creating sets of creatures#
for x in range(0,100):
Plants.append(Plant(Protoplant()))
for x in range (0,20):
Preys.append(Prey(Protoprey()))
for x in range (0,5):
Predators.append(Predator(Protopredator()))
###EXECUTE PROGRAM###
while cycles > 0:
for pred in Predators:
CHASE(pred,SEEK(pred,Preys,1),Preys)
DEPLETE (pred)
SPLIT(pred,Predators,Predator)
for pre in Preys:
pre.ACT()
DEPLETE(pre)
SPLIT(pre,Preys,Prey)
pre.Coord[0]=pre.Coord[0]%100
pre.Coord[1]=pre.Coord[1]%100
for plan in Plants:
plan.health=plan.health+10.0/resolution
plan.DEATH()
SPLIT(plan,Plants,Plant)
plan.Coord[0]=plan.Coord[0]%100
plan.Coord[1]=plan.Coord[1]%100
print(cycles)
print('plants:', len(Plants))
print('prey:', len(Preys))
print('predators:', len(Predators))
cycles=cycles-1.0/resolution
What has me stumped here is that in the line just before 128, the CHASE function calls the metabolism attribute as well, and does so without a hitch.
I became even more confused after running the debugger: in debug mode (in the eclipse platform), I enter the DECAY function, metabolism is right there in the list of the class instance's attributes, and the debugger seems to execute line 102 without a hitch, returning to the deplete function. I hit "step into" two more times after this, and the program crashes with the error:
Traceback (most recent call last):
File "C:\Users\John Smith\Documents\workspace\stand-alone scripts\src\Evo_classes.py", line 133, in <module>
DEPLETE (pred)
File "C:\Users\John Smith\Documents\workspace\stand-alone scripts\src\Evo_classes.py", line 107, in DEPLETE
creature.health=creature.health-2*creature.metabolsim/resolution
AttributeError: Predator instance has no attribute 'metabolsim'
sorry about the long post, but I wasn't sure which pieces of information would be relevant. Thank you for your time and assistance.