Calling method inside __str__ function in python class - python

'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()

Related

How is 'moveSpeed' used here without being defined anywhere?

I found this pygame project online and was curious how 'moveSpeed' is being used as a number? like below?
def move(self, moveSpeed):
self.x -= moveSpeed
class HurdleManager:
def __init__(self, scale, spawnRange):
self.img = transform.scale(image.load('homework.png'), (7 * scale, 15 * scale))
self.spawnRange = spawnRange
self.hurdleList = []
self.scale = scale
def update(self, doSpawn, moveSpeed):
if doSpawn:
self.spawn()
self.manage(moveSpeed)
def manage(self, moveSpeed):
hurdles2 = []
for hurdle in self.hurdleList:
hurdle.update(moveSpeed)
if hurdle.onScreen():
hurdles2.append(hurdle)
self.hurdleList = hurdles2
spawnTick = 0
def spawn(self):
if self.spawnTick >= self.spawnRange[1]:
newHurdle = HurdleClass(windowX, self.img, 7 * self.scale, 15 * self.scale)
self.hurdleList.append(newHurdle)
self.spawnTick = 0
elif self.spawnTick > self.spawnRange[0]:
if random.randint(0, self.spawnRange[1] - self.spawnRange[0]) == 0:
newHurdle = HurdleClass(windowX, self.img, 7 * self.scale, 15 * self.scale)
self.hurdleList.append(newHurdle)
self.spawnTick = 0
self.spawnTick += 1
hurdleManager = HurdleManager(3, (45, 90))
class HurdleClass:
def __init__(self, x, img, width, height):
self.x = x
self.img = img
self.width = width
self.height = height
self.y = ground - height
def update(self, moveSpeed):
self.move(moveSpeed)
self.show()
def move(self, moveSpeed):
self.x -= moveSpeed
def show(self):
window.blit(self.img, (self.x, self.y))
def onScreen(self):
if self.x + self.width > 0:
return True
else:
return False
def move(self, moveSpeed):
def move says "I'm creating a function definition here. When I've finished defining it, I'd like the function to be bound to the name "move" in the current scope. Also, the function can use bindings from the current scope."
(self, moveSpeed) says "To run this function, I need two arguments. The first one is called self and the second one is called moveSpeed."
An argument is also known as a parameter. Just like when being asked to cut a cake, you might ask "Which cake?" and "Which knife?". In most programming languages, you pass parameters (also known as arguments) in the order each is declared. For example, given:
def cut(cake, knife):
...
writing cut(a, b) would "call" cut with the caller's "a" bound to the called function's "cake" variable and with the caller's "b" bound to the called function's "knife" variable.
In Python, you can also give the names of arguments explicitly. For example, cut(cake=a, knife=b) would do the same thing. These are called "keyword arguments." You don't need to pass things in declaration order when you use keyword arguments. For example, cut(knife=b, cake=a) would do the same thing as well.

Why does trying to set "points" via Python properties cause infinite recursion?

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

Create a picklable Python class

I am trying to create some custom Python classes for my application. When I try to debug my code I can not pick the instances of my custom classes, I receive the error "Object XXX is not picklable".
I found this page https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled but I don't understand how I should implement the methods that make my class picklable.
For example how would you modify the following classes so that I can pick instances of them?
class Point3D:
def __init__ (self, x, y, z):
self.x = x
self.y = y
self.z = z
def move(self, vector):
self.x += vector.x
self.y += vector.y
self.z += vector.z
return
def isValidPoint(self):
isNotValid = False
isNotValid = math.isnan(self.x) or math.isnan(self.y) or math.isnan(self.z)
return not isNotValid
And
class PointCloud3D:
def __init__ (self):
self.points = []
def getNumberOfPoints(self):
return len(self.points)
def addPoint(self, point):
self.points.append(point)
return
def addPointCloud3D(self, additionalPointCloud3D):
for self.point in additionalPointCloud3D:
self.addPoint(point)
def getCloudCenter(self):
numberOfPoints = self.getNumberOfPoints()
centersSumX = 0
centersSumY = 0
centersSumZ = 0
for point in self.points:
centersSumX = centersSumX + point.x
centersSumY = centersSumY + point.y
centersSumZ = centersSumZ + point.z
centerX = centersSumX/numberOfPoints
centerY = centersSumY/numberOfPoints
centerZ = centersSumZ/numberOfPoints
center = Point3D(float(centerX), float(centerY) , float(centerZ))
return center
While here you can find the code that I am trying to debug:
from classDatabase import Point3D, PointCloud3D
testPoint1 = Point3D(1.5, 0.2, 2.3)
testPoint2 = Point3D(3.5, 1.2, 5.3)
testPointCloud3D = PointCloud3D()
testPointCloud3D.addPoint(testPoint1)
testPointCloud3D.addPoint(testPoint2)
Finally a screenshot of the issue:

Python: maximum recursion depth exceeded while calling a Python object when calling copy function

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.

Changed all objects value in list in object changed instead of only one

I have problem with my program. When I try to change object value (which is in list) I changed all object's value in that list.
My code:
class obj:
def __init__(self, x, y):
self.x = x
self.y = y
def mirrorise(self, mirror):
self.mirror = mirror
if self.mirror.type == 'teleporterx':
self.x -= (self.x-(self.mirror.x+self.mirror.x1/2))*2
class person(obj):
def __init__(self, x, y):
self.x = x
self.y = y
self.pos = [obj(self.x, self.y)]
def mirrored(self, mirrors):
self.count = 0
self.mirrors = mirrors
self.mens = 0
for men in self.pos:
self.mens += 1
for mirror in self.mirrors:
if self.count == 1:
for men in range(self.mens):
self.pos.append(self.pos[men])
self.count = 1
self.count = 0
for men in self.pos:
men.mirrorise(self.mirrors[self.count])
self.count += 1
if self.mirrors[self.count-1] == self.mirrors[-1]:
self.count = 0
class mirror:
def __init__(self, x, y, x1, y1, type):
self.x = x
self.y = y
self.x1 = x1
self.y1 = y1
self.type = type
After in code I call person object called I and two mirror objects called mirr and mirr2 with type teleportx. When I write:
I.mirrored([mirr, mirr2])
it changes x for all objects in I.pos. If I write
I.pos[3].mirrorise(mirr)
it still changes all x. Even if I write:
I.pos[3].x -= (I.pos[3].x-(mirr2.x+mirr.x1/2))*2
it changes all values. So, is it some Python rule or I have mistake?
You are adding references to your one original obj() instance:
self.pos.append(self.pos[men])
That's not a copy; that's just another reference to the same object.
Create a new obj() instance instead:
self.pos.append(obj(self.pos[men].x, self.pos[men].y))

Categories

Resources