This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
I have a doubt about storing a class variables in a second variable, in order to be called later.
This is my code (simplified to be readable):
class Agent(object):
def __init__(self):
self.actual = []
class Play(object):
def __init__(self):
self.x = 0.45 * 400
self.y = 0.5 * 400
self.position = []
self.position.append([self.x, self.y])
self.x_change = 20
self.y_change = 0
def do_move(self, move, x, y):
move_array = [self.x_change, self.y_change]
if move == 1 and self.x_change == 0: # right
move_array = [20, 0]
self.x_change, self.y_change = move_array
self.x = x + self.x_change
self.y = y + self.y_change
self.update_position(self.x, self.y)
def update_position(self, x, y):
self.position[-1][0] = x
self.position[-1][1] = y
def run():
agent = Agent()
player1 = Play()
agent.actual = [player1.position]
print(agent.actual[0])
i = 1
player1.do_move(i, player1.x, player1.y)
print(agent.actual[0])
run()
>> [[180.0, 200.0]]
>> [[200.0, 200.0]]
This is what I cannot understand. Why, if agent.actual stores the player.position and it is not modified after agent.actual = [player1.position], its value actually changes between the two print()?
I modify player.position, but not agent.actual, which means it should stay the same. I cannot figure this out!
EDIT:
I tried, as suggested, with the following methods:
agent.actual = player1.position.copy()
agent.actual = player1.position[:]
agent.actual= list(player1.position)
import copy
agent.actual = copy.copy(player1.position)
agent.actual = copy.deepcopy(player1.position)
All these methods always return, as before, two different values:
>> [[180.0, 200.0]]
>> [[200.0, 200.0]]
Player.position is list, which means it's mutable type. If you put this list in another list, Python makes a reference to it, not a copy.
When you add/delete/change items in the list, it will change everywhere the reference is hold.
You need to make a copy when you assign to agent.actual. Look at the copy module in Python or restructure your code (Hint: tuple is immutable type)
Related
I have a task wherein I am to determine if a Point(x,y) is closer than some amount to any of the Points that are stored in a Python array. Here is the test code:
from point import *
collection = []
p1 = Point(3,4)
collection.append(p1)
print(collection)
p2 = Point(3,0)
collection.append(p2)
print(collection)
p3 = Point(3,1)
radius = 1
print( collection[1] ) # This works, BTW
p = collection[1]
print( p ) # These two work also!
for i in collection:
p = collection[i] # THIS FAILS
if distance(p3,p) < 2*radius:
print("Point "+collection[i]+" is too close to "+p3)
The file point.py contains:
import math
class Point:
'''Creates a point on a coordinate plane with values x and y.'''
COUNT = 0
def __init__(self, x, y):
'''Defines x and y variables'''
self.X = x
self.Y = y
def move(self, dx, dy):
'''Determines where x and y move'''
self.X = self.X + dx
self.Y = self.Y + dy
def __str__(self):
return "Point(%s,%s)"%(self.X, self.Y)
def __str__(self):
return "(%s,%s)"%(self.X,self.Y)
def testPoint(x=0,y=0):
'''Returns a point and distance'''
p1 = Point(3, 4)
print (p1)
p2 = Point(3,0)
print (p2)
return math.hypot(p1, p2)
def distance(self, other):
dx = self.X - other.X
dy = self.Y - other.Y
return math.sqrt(dx**2 + dy**2)
#p1 = Point(3,4)
#p2 = Point(3,0)
#print ("p1 = %s"%p1)
#print ("distance = %s"%(distance(p1, p2)))
Now, I have a couple of questions here to help me understand.
In the test case, why doesn't the print of the array use the str function to
print the Point out as '(x,y)'?
In ' if distance(p3,collection[i]) ', why isn't collection[i] recognized as a Point which the distance function is expecting?
In the 'p = collection[i]' statement, why does python complain that the list indices must be integers or slices, not Point?
It appears that the collection array is not recognized as an array of Point instances. I'm confused as in other OO languages like Objective-C or Java, these are simple things to do.
Take a look at this question. __repr__() is used when rendering things in lists.
(and 3.) I'm not sure if I follow your questions, but the problem you have in your code is that Python hands you the object itself, not the index. So:
for i in collection:
p = collection[i] # THIS FAILS
if distance(p3,p) < 2*radius:
print("Point "+collection[i]+" is too close to "+p3)
should be:
for p in collection:
if distance(p3,p) < 2*radius:
print(f"Point {p} is too close to {p3}")
I have an list of objects called character like that:
characters=[character(0,0,20,20,keys1),character(50,50,50,50,keys2),character(200,200,100,20,keys1)]
where character class is defined as:
class character():
def __init__(self,x,y,w,h,keys=keys1):
self.x = x
self.y = y
self.w = w
self.h = h
self.keys = keys
self.vel = 200 /math.sqrt(self.w*self.h)
self.crashed=False
# I need an list to use here in a function of my "character" class
# my list must have all the elements in my initial list but self
what I mean is like
characters[0].myFunction() must have a list of [characters[1],characters[2]]
which is characters =[character(50,50,50,50,keys2),character(200,200,100,20,keys1)]
you have to pass as an argument to your .myFunction the full list to know from which list to exclude/filter self:
class character():
def __init__(self,x,y,w,h,keys=keys1):
self.x = x
self.y = y
self.w = w
self.h = h
self.keys = keys
self.vel = 200 /math.sqrt(self.w*self.h)
self.crashed = False
def __repr__(self):
return 'charcter({}, {}, {}, {}, {})'.format(
self.x, self.y, self.w, self.h, self.keys)
def myFunction(self, characters):
return [e for e in characters if e != self]
print(characters[0].myFunction(characters))
output:
[charcter(50, 50, 50, 50, keys2), charcter(200, 200, 100, 20, keys1)]
I Understand what you want but there are a few issues with your code that I decided to fix for you i guess. The first is to remember just for your sake that when making classes make the first letter upper case. Next your key creation does not make any sense because keys1 doesnt exsist. I assumed it to be a string in my example. Next I created an str function for your class so it can output the characters somehow so its not only the memory address. Next I created the function you want but it will be in the format
x = myFunc(characters[0], characters)
and on top of that if you print x it will give you a list of memory addresses and therefore you must loop through and print each character specifically to see which one it is. Here is the final code.
import math
class Character():
def __init__(self,x,y,w,h,keys="keys1"):
self.x = x
self.y = y
self.w = w
self.h = h
self.keys = keys
self.vel = 200 /math.sqrt(self.w*self.h)
self.crashed=False
# I need an list to use here in a function of my "character" class
# my list must have all the elements in my initial list but self
def __str__(self):
return "Character x:{}, y:{}, w:{}, h:{}, key:{}".format(self.x, self.y, self.w, self.h, self.keys)
def myFunc(chars, characters):
characters_copy = characters[:]
if chars in characters_copy:
ind = characters_copy.index(chars)
characters_copy.pop(ind)
return characters_copy
characters = [Character(0,0,20,20), Character(50,50,50,50), Character(200,200,100,20)]
x = myFunc(characters[0], characters)
for i in x:
print(i)
I believe this is somewhat what you wanted, I added the changes so its easier for me and you. But you should be able to work with this.
I'm creating an object Block which I assign an X and Y position among other arguments, I want to be able to move it through a method move() by x and y units and have the original x and y position updated, so as to when I call say xyRange() before moving the object, I get the original x, y position, and when I do so after move(), I get the updated x, y position.
Below is what I've tried but I think I'm missing some crucial aspect because I get an error that my object 'Block' has no such attribute.
def X(self):
x = self.xPosition
return x
def Y(self):
y = self.yPosition
return y
def xyRange(self):
xRange = self.X() + self.toBlock.absX()
yRange = self.Y() + self.toBlock.absY()
return xRange, yRange
def move(self, moveX=None, moveY=None):
absX = self.absX()
absY = self.absY()
self.moveX = moveX
if(self.moveX == None):
moveX = 0
self.moveY = moveY
if(self.moveY == None):
moveY = 0
absoluteX = absX + moveX
absoluteY = absY + moveY
return absoluteX, absoluteY
def absX(self):
absoluteX = self.X() + self.toBlockId.absX()
return absoluteX
def absY(self):
absoluteY = self.Y() + self.toBlockId.absY()
return absoluteY
So I have functions X() and Y() to take in the parameters from the constructor and be able to manipulate them in other functions, also absX() and absY() to track the objects actual position in the grid and xyRange() function that basically does the same thing but just returns the tuple of x, y parameter (lets say for convenience sake). But I can't seem to figure out how to update my original X and Y positions.
Say I start with a block1.xyRange() that returns (2, 2)
then I block1.move(2, 2), which you'd expect when I ran block1.xyRange() again, would return (4, 4). But if I try adding the self.moveX and self.moveY parameters from the move function to the X() and Y() function, I get an error saying that object 'Block' has no attribute 'moveX' or 'moveY'. I assume that this is because its calling itself. But I can't figure out how to fix it.
Any suggestions would be greatly appreciated.
in your move method, you forgot to set the updated (absoluteX and absoluteY) values to the object fields (self.xPosition and self.yPosition). That is why you never get the updated value.
def move(self, moveX=None, moveY=None):
self.moveX = moveX
if(self.moveX == None):
moveX = 0
self.moveY = moveY
if(self.moveY == None):
moveY = 0
self.absoluteX = self.absX() + moveX
self.absoluteY = self.absY() + moveY
return self.absoluteX, self.absoluteY
I create a class named point as following:
class point:
def __init__(self):
self.x = 0
self.y = 0
and create a list of point instances:
p1 = point()
p1.x = 1
p1.y = 1
p2 = point()
p2.x = 2
p2.y = 2
p_list = []
p_list.append(p1)
p_list.append(p2)
Now I'd like remove from the list the instance which x = 1 and y = 1, how can I do this?
I try to add a __cmp__ method for class point as following:
class point:
def __init__(self):
self.x = 0
self.y = 0
def __cmp__(self, p):
return self.x==p.x and self.y==p.y
But the following code does not work
r = point()
r.x = 1
r.y = 1
if r in p_list:
print('correct')
else:
print('wrong') # it will go here
p_list.remove(r) # it reports 'ValueError: list.remove(x): x not in list'
Your __cmp__ function is not correct. __cmp__ should return -1/0/+1 depending on whether the second element is smaller/equal/greater than self. So when your __cmp__ is called, it returns True if the elements are equal, which is then interpreted as 1, and thus "greater than". And if the elements are non-equal, it returns False, i.e. 0, which is interpreted as "equal").
For two-dimensional points, "greater than" and "smaller than" are not very clearly defined, anyway, so you can just replace your __cmp__ with __eq__ using the same implementation. Your point class should be:
class point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __eq__(self, p):
return self.x==p.x and self.y==p.y
When you're checking if r is in p_list you create a new instance of point, thus that instance of point will not be in the list (it has a different location in memory).
This function works to remove a point where x and y are 1:
for idx, p in enumerate(p_list):
if p.x==1 and p.y==1:
del p_list[idx]
Python dictionaries have always confused me.
I have 3 dictionaries:
left_dict = {"N":"W", "W":"S", "S":"E", "E":"N"}
right_dict = {"N":"E", "E":"S", "S":"W", "W":"N"}
turn_dict = {"N":"S", "E":"W", "S":"N", "W":"E"}
I have a class Robot which is initialized as such:
class Robot:
def __init__(self, team, x, y, direction):
self.team = team
self.health = 50
self.x = x
self.y = y
self.direction = direction
In this class I have a method that changes the direction.
def left90(self):
self.direction = left_dict <---- **is this how I would change the direction**
I believe what you are looking for is:
def left90(self):
self.direction = left_dict[self.direction]