Why does trying to set “points” via Python properties cause infinite recursion?
Using Python 3
import Task
myTask = Task.Task("Test",-5)
myTask.points = -7
print(myTask)
class Task:
def __init__(self,name="",points=0,times_done=0):
self.name = name
self.points = points
self.times_done = times_done
#property
def points(self):
return self.points
#points.setter
def points(self, points):
if (points < 0):
self.points = 0
else:
self.points = points
def __str__(self):
return "The task '" + self.name + "' is worth " + str(self.points) + " and has been completed " + str(self.times_done) + " times."
When it tries constructing it with value -5 (which should set it to 0, via the property), it infinitely recurses on the line self.points = points in the setter function/decoration #points.setter.
Thanks!
Because self.points = ... call the setter; inside the setter, self.points = ... is executed which call the setter; recursion repeated until stack overflow.
By using other name, you can prevent the recursion: self._points for example.
Or instead of using self.points = ..., use self.__dict__['points'] = .. (same for getter):
#property
def points(self):
return self.__dict__['points']
#points.setter
def points(self, points):
if points < 0:
self.__dict__['points'] = 0
else:
self.__dict__['points'] = points
# self.__dict__['points'] = max(0, points)
That's because inside your property setter, it calls itself again:
#points.setter
def points(self, points):
if (points < 0):
self.points = 0 # call itself again here
else:
self.points = points # call itself again here
You need another field to store the actually value when you use property, and it would be better to be a "private" field:
class Task(object):
def __init__(self,name="",points=0,times_done=0):
self.name = name
self.points = points
self.times_done = times_done
#property
def points(self):
return self._points
#points.setter
def points(self, points):
if (points < 0):
self._points = 0
else:
self._points = points
Related
So I'm just doing a learning project and I need some help.
class Car:
def __init__(self):
self.speed = 0
self.color = ""
self.weight = 0
self.engine = 4
self.name = ""
self.mpg = 25
self.maintenanceLog = []
self.oilChanges = []
#mutator methods
def setSpeed(self, sp):
self.speed = sp
def setColor(self, cl):
self.color = cl
def setWeight(self, w):
self.weight = w
def setEngine(self, e):
self.engine = e
def setName(self, n):
self.name = n
def setMpg(self, mpg):
self.mpg = mpg
def addOilChange(self, oc):
self.oilChanges.append(oc)
def addMaintenance(self, ml):
self.maintenanceLog.append(ml)
#accessor methods
def getSpeed(self):
return self.speed
def getColor(self):
return self.color
def getWeight(self):
return self.weight
def getEngine(self):
return self.engine
def getName(self):
return self.name
def getMPG(self):
return self.mpg
def getAllOilChanges(self):
print("")
print("----------OIL CHANGES----------")
for oc in self.oilChanges:
print(oc)
def getMaintenanceLogs(self):
print("")
print("----------MAINTENANCE LOGS----------")
for ml in self.maintenanceLog:
print(ml)
def setInfo(car):
car.setSpeed(int(input(f"Speed of {car}")))
car.setWeight(int(input(f"Weight of {car}")))
car.setName(input(f"Name of {car}"))
car.setColor(input(f"Color of {car}"))
car.setEngine(int(input(f"Engine of {car}")))
car.setMpg(int(input(f"Miles per Gallon of {car}")))
def getInfo(car):
print(f"Speed of {car} is {car.getSpeed()} mph.")
print(f"Weight of {car} is {car.getWeight()} pounds.")
print(f"Name of {car} is {car.getName()}.")
print(f"Color of {car} is {car.getColor()}.")
print(f"Engine cylinders of {car} are {car.getEngine()}.")
print(f"Miles per Gallon of {car} is {car.getMPG()}.")
def main():
carList = []
Object1= Car()
carList.append(Object1)
print(carList)
for obj in carList:
setInfo(obj)
getInfo(obj)
main()
Thats's the code, now, whenever I run it, I want to get asked Speed of Object1:
Instead, I get asked Speed of <main.Car object at 0x0000024B093CEFD0>:
How can I see the name of the object instead of that hash value... I want to keep adding objects with the class Car and then pass them through a loop to fill in the information regarding the object, but if the list of objects was [Object 1, Object 2, Object 3... Object N] I want it to refer to that name (Object 1) instead of <main.Car object at 0x0000024B093CEFD0>
You can pass the name to use in the prompts as an argument to setInfo().
def setInfo(car, name=None):
if name is None:
name = car.name
car.setSpeed(int(input(f"Speed of {name}")))
car.setWeight(int(input(f"Weight of {name}")))
car.setName(input(f"Name of {name}"))
car.setColor(input(f"Color of {name}"))
car.setEngine(int(input(f"Engine of {name}")))
car.setMpg(int(input(f"Miles per Gallon of {name}")))
and then use that in the loop.
for i, obj in enumerate(carList, 1):
setInfo(obj, f"Object {i}")
getInfo(obj)
I am currently creating my genetic algorithm and want to print the number of generations at the very end of the program when it finishes. However I am unsure how to access the counter variable that is the number of generations when it is outside of the class and method. So for example, at the end it would be like
Generation 100, average fit 18966, best fit 18947
Your best chromosone at generation 100
'\x06pzÂ\x8cYÆr¯n0q\x07l¿M8\x93Þ\x19\x87"\x01\x85\x1er\x89[F_VyER\x9b\x0bm=)\x9a\x9a¿¥\x10F\x12A\x84\x0fZ^\x14\x99\x8a4®\x9f¿*\\\xa0yi\x19E\x8aÇ+6(_<¾£cO~\x9c\x99\x932\x06\x0f\x82\x7f¤\x808xǸñA\x13\x0e<%\x06ÿ#í\x91Pô\x98 ®\r\x1b}\x89y¦\x0cqAK\tp\x95\x99ÔNj=Wn\x16\x94\x0cu!¯ñ\x13Qü[e8_ÂóU\x10\x1av_+%Q_¡ù\x87=\x08~ciÎ_Ï[\x8f#AëT\x14©qG\x89#Z«L\x9b¢\x94WL\x1dV¶R03\x84æ^ßr\x1fÃÈ\x1d\x8e Læª&®x\x94?TAÒD\x14£i\x82J\x15=w~\x03\x0c\xa0¾5\x02f5T\x91ol¢bIÞfk¬¡27W16(}6\x92\x87\n®xm0\x1a\n<8(à}ñ\x88̾\x17g\x9bj6\x8fI&\x12\x9aÂ\x9a_F\x1a\r[\x1dK\x15<.±DjcIy`98d>\x197Z\x91£%tIJ\x820\x93|\x07\x8dnÚ QÂ!Pf\x1d\nåòf\x91\x1d#S¾|\x9ff[d>O=T$ݶI\x9e»QÛÂ\x1d"¿U=û´F÷\x83C}wA\xa0É\x8aD\x93x»\x85\x7f\x14^\x0eL'
done:
100 generations
How do I exactly access the 100 from the method in the class?
import random
class GeneticAlgorithm(object):
def __init__(self, genetics):
self.genetics = genetics
pass
def run(self):
population = self.genetics.initial()
while True:
fits_pops = [(self.genetics.fitness(ch), ch) for ch in population]
if self.genetics.check_stop(fits_pops): break
population = self.next(fits_pops)
pass
return population
def next(self, fits):
parents_generator = self.genetics.parents(fits)
size = len(fits)
nexts = []
while len(nexts) < size:
parents = next(parents_generator)
cross = random.random() < self.genetics.probability_crossover()
children = self.genetics.crossover(parents) if cross else parents
for ch in children:
mutate = random.random() < self.genetics.probability_mutation()
nexts.append(self.genetics.mutation(ch) if mutate else ch)
pass
pass
return nexts[0:size]
pass
class GeneticFunctions(object):
def probability_crossover(self):
r"""returns rate of occur crossover(0.0-1.0)"""
return 1.0
def probability_mutation(self):
r"""returns rate of occur mutation(0.0-1.0)"""
return 0.0
def initial(self):
r"""returns list of initial population
"""
return []
def fitness(self, chromosome):
r"""returns domain fitness value of chromosome
"""
return len(chromosome)
def check_stop(self, fits_populations):
r"""stop run if returns True
- fits_populations: list of (fitness_value, chromosome)
"""
return False
def parents(self, fits_populations):
r"""generator of selected parents
"""
gen = iter(sorted(fits_populations))
while True:
f1, ch1 = next(gen)
f2, ch2 = next(gen)
yield (ch1, ch2)
pass
return
def crossover(self, parents):
r"""breed children
"""
return parents
def mutation(self, chromosome):
r"""mutate chromosome
"""
return chromosome
pass
if __name__ == "__main__":
"""
example: Mapped guess prepared Text
"""
class GuessText(GeneticFunctions):
def __init__(self, target_text,
limit=100, size=100,
prob_crossover=0.9, prob_mutation=0.2):
self.target = self.text2chromo(target_text)
self.counter = 0
self.limit = limit
self.size = size
self.prob_crossover = prob_crossover
self.prob_mutation = prob_mutation
pass
# GeneticFunctions interface impls
def probability_crossover(self):
return self.prob_crossover
def probability_mutation(self):
return self.prob_mutation
def initial(self):
return [self.random_chromo() for j in range(self.size)]
def fitness(self, chromo):
# larger is better, matched == 0
return -sum(abs(c - t) for c, t in zip(chromo, self.target))
def check_stop(self, fits_populations):
self.counter += 1
if self.counter % 100 == 0:
best_match = list(sorted(fits_populations))[-1][1]
fits = [f for f, ch in fits_populations]
best = -(max(fits))
ave = -(sum(fits) / len(fits))
print(
"Generation %3d, average fit %4d, best fit %4d" %
(self.counter, ave, best,
))
print("Your best chromosone at generation %3d" % self.counter)
print("%r" % self.chromo2text(best_match))
pass
return self.counter >= self.limit
def parents(self, fits_populations):
while True:
father = self.tournament(fits_populations)
mother = self.tournament(fits_populations)
yield (father, mother)
pass
pass
def crossover(self, parents):
father, mother = parents
index1 = random.randint(1, len(self.target) - 2)
index2 = random.randint(1, len(self.target) - 2)
if index1 > index2: index1, index2 = index2, index1
child1 = father[:index1] + mother[index1:index2] + father[index2:]
child2 = mother[:index1] + father[index1:index2] + mother[index2:]
return (child1, child2)
def mutation(self, chromosome):
index = random.randint(0, len(self.target) - 1)
vary = random.randint(-5, 5)
mutated = list(chromosome)
mutated[index] += vary
return mutated
# internals
def tournament(self, fits_populations):
alicef, alice = self.select_random(fits_populations)
bobf, bob = self.select_random(fits_populations)
return alice if alicef > bobf else bob
def select_random(self, fits_populations):
return fits_populations[random.randint(0, len(fits_populations)-1)]
def text2chromo(self, text):
return [ord(ch) for ch in text]
def chromo2text(self, chromo):
return "".join(chr(max(1, min(ch, 255))) for ch in chromo)
def random_chromo(self):
return [random.randint(1, 255) for i in range(len(self.target))]
pass
GeneticAlgorithm(GuessText("""The smartest and fastest Pixel yet.
Google Tensor: Our first custom-built processor.
The first processor designed by Google and made for Pixel, Tensor makes the new Pixel phones our most powerful yet.
The most advanced Pixel Camera ever.
Capture brilliant color and vivid detail with Pixels best-in-class computational photography and new pro-level lenses.""")).run()
print('done:')
print("%3d " 'generations' % counter)
pass
Define the GuessText first. Then access the counter.
gt = GuessText("""The smartest and fastest Pixel yet.
Google Tensor: Our first custom-built processor.
The first processor designed by Google and made for Pixel, Tensor makes the new Pixel phones our most powerful yet.
The most advanced Pixel Camera ever.
Capture brilliant color and vivid detail with Pixels best-in-class computational photography and new pro-level lenses.""")
GeneticAlgorithm(gt).run()
print('done:')
print("%3d " 'generations' % gt.counter)
class PolygonInteriorAngle(object):
def __init__(self, x):
self.x = self
def FindInteriorAngle(self):
degrees = int((x - 2) * 180)
interior = int(degrees / x)
return interior
def PrintInterior(self):
print("interior angle: " + str(self.FindInteriorAngle()))
class PolygonExteriorAngle(object):
def __init__(self, x):
self.x = self
def FindExteriorAngle(self):
exterior = int(360 / x)
return exterior
def PrintExterior(self):
print("exterior angle: " + str(self.FindExteriorAngle()))
class AngleAddition(object):
def __init__(self, x):
self.x = self
def Add(self):
sum = int(interior + exterior)
return sum
def PrintAdd(self):
print("sum of interior and exterior: " + str(self.Add()))
if __name__ == "__main__":
x = int(input("enter: "))
intObj = PolygonInteriorAngle(x)
intObj.FindInteriorAngle()
intObj.PrintInterior()
extObj = PolygonExteriorAngle(x)
extObj.FindExteriorAngle()
extObj.PrintExterior()
addObj = AngleAddition(x)
addObj.Add()
addObj.PrintAdd()
both classes (PolygonInteriorAngle and PolygonExteriorAngle) work fine, they print what they're expected to. what i want to do in the AngleAddition class is to add both of the final values (interior and exterior) that you get from the other two classes. i think it's pretty inefficient putting them in different classes, but that's what my computer science teacher asked me to and i'm not sure how to use a value from another class in a new class. if you do x = 6, you'll get 120 and 60. with AngleAddition i want to print 180.
General comments:
You need to check very carefully the variables in your instance methods. example:
def Add(self):
sum = int(interior + exterior)
return sum
Both interior and exterior are not specified in the instance method arguments.
I agree with User: Tim Roberts's comment. Either you make a base class "angle" and let the "interior/exterior angle" class inherit from the "angle" class, or just use angle class for both interior/exterior angles. It depends on how you want to write the __init__ method for interior/exterior angle classes.
Note that I overrode the magic method to perform the sum of two angles. There are other ways of doing that cause in my way the + operator is being redefined.
Anyways:
class AngleBase:
def __init__(self,angle):
self.angle=angle
def __add__(self,angleobj):
return int(self.angle+angleobj.angle)
class PolygonInteriorAngle(AngleBase):
def __init__(self, side):
degrees = int((side - 2) * 180)
interior = int(degrees / side)
AngleBase.__init__(self,interior)
def FindInteriorAngle(self):
return self.angle
def PrintInterior(self):
print("interior angle: " + str(self.angle))
class PolygonExteriorAngle(AngleBase):
def __init__(self, side):
exterior = int(360 / side)
AngleBase.__init__(self,exterior)
def FindExteriorAngle(self):
return self.angle
def PrintExterior(self):
print("exterior angle: " + str(self.angle))
class AngleAddition:
def __init__(self, x):
pass
def Add(self,interior, exterior):
sum = int(interior + exterior)
return sum
def PrintAdd(self,interior, exterior):
print("sum of interior and exterior: " + str(self.Add(interior, exterior)))
if __name__ == "__main__":
x = int(input("enter: "))
intObj = PolygonInteriorAngle(x)
print(intObj.angle)
intObj.FindInteriorAngle()
intObj.PrintInterior()
extObj = PolygonExteriorAngle(x)
extObj.FindExteriorAngle()
extObj.PrintExterior()
addObj = AngleAddition(x)
addObj.Add(extObj,intObj)
addObj.PrintAdd(extObj,intObj)
'List' object has no attribute 'points' is the error I'm getting. I think I'm not calling points correctly inside the __str__ function, but don't know how to fix it. Before, I had points defined before __str__ and had the same error.
class Persons(object):
def __init__(self,name,radius,home_universe,x,y,dx,dy,current_universe,rewards):
self.name = name
self.radius = radius
self.home_universe = home_universe
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.current_universe = current_universe
self.rewards = rewards
def __str__(self):
return '{} of {} in universe {}\n at ({},{}) speed ({},{}) with {} rewards and {} points'.\
format(self.name, self.home_universe, self.current_universe, self.x, self.y, self.dx,\
self.dy, len(self.rewards), self.rewards.points())
def points(self):
cnt = 0
if len(self.rewards) == 0:
return 0
else:
for reward in self.rewards:
cnt += reward[2]
return cnt
You use self.rewards.points() but you have only self.points().
Use self.points()
I have a class Particle which has some parameters and attributes, as you can see below. But, when it does get to the function setter for position, and it executes the copy() function, I get the error message : RuntimeError: maximum recursion depth exceeded while calling a Python object. I've tried different options, like deepcopy(), or import sys sys.setrecursionlimit(10000) , but none of them worked... Does anyone have any idea? This is my code:
def initCost(n):
a = random.randint(0,10) #gram.
b = random.randint(0,5) #price
return [random.randint(0,a*b) for i in range(n)]
costs = initCost(10)
class Particle:
def __init__(self, n, maxWeight):
self.position = [random.randint(0,1) for i in range(n)] #position
self.velocity = [0 for i in range(n)] #velocity
#self.fit = self.fitness(self.position)
self.bp = self.position.copy() #best position
self.bf = self.fit #best fitness
self.evaluate()
def fit(self, x):
fitt = 0
for i in range(len(x)-1):
if (x[i] == 1):
fitt = fitt + costs[i]
return fitt
def evaluate(self):
""" evaluates the particle """
self.fitness = self.fit(self.position)
#property
def position(self):
return self.position
#property
def bp(self):
return self.bp
#property
def bf(self):
return self.bf
#position.setter
def position(self, newPosition):
self.position = newPosition.copy()
#self.position = newPosition[:]
self.evaluate()
# automatic update of particle's memory
if (self.fit<self.bf):
self.bp = self.position
self.bf = self.fit
It looks like you're trying to use position as the name of both the property and the ordinary attribute backing it. For example,
#position.setter
def position(self, newPosition):
self.position = newPosition.copy()
# ^^^^^^^^^^^^^^^
This attempt to set self.position will use the setter you're defining! Similarly,
#property
def position(self):
return self.position
This getter just calls itself!
Trying to use self.position inside the position property definition won't bypass the property. If you want a "regular" attribute backing the property, call it something else, like self._position or something.