Python checking if object member value is in list - python

I have this class called Point:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
I have a list with Point objects and I call a method to check if it's in the list like this:
def isInList(self, list, point):
for cell in list:
if(cell == point):
return True
return False
However, it never goes inside the if statement; so it always returns false. I know for a fact that a point that matches has to be in the list due to a visualization I have showing up in my program. What am I doing wrong?
I call these two methods to make a list of Point. I pass cells and directions like this (called multiple times with different points and directions):
point = Point(2, 4)
direction = Direction.UP
newList = self.setCells(point, direction)
def setCells(self, point, direction):
pointList = []
index = 0
done = False
while index < 20 and done == False:
newPoint = self.getNextCell(point, direction)
if(point not in pointList):
pointList.append(newPoint)
point = pointList[len(pointList)-1]
index += 1
else:
done = True
return pointList
def getNextCell(self, point, direction):
if(direction == Direction.UP):
return Point(point.x-1, point.y, Direction.UP)
elif(direction == Direction.DOWN):
return Point(point.x+1, point.y, Direction.DOWN)
elif(direction == Direction.LEFT):
return Point(point.x, point.y-1, Direction.LEFT)
elif(direction == Direction.RIGHT):
return Point(point.x, point.y+1, Direction.RIGHT)
Direction is an enum:
class Direction(Enum):
NONE = 1
UP = 2
DOWN = 3
LEFT = 4
RIGHT = 5

Unfortunately the code from the OP's question seems to contain functions that were meant to be bound to an object (setCells and getNextCell), but are exhibited without their class. Furthermore the call to the constructor of Point in getNextCells had an additional argument (the direction), which I removed. Therefore I am considering the following code:
import enum
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def setCells(point, direction):
pointList = []
index = 0
done = False
while index < 20 and done == False:
newPoint = getNextCell(point, direction)
if(point not in pointList):
pointList.append(newPoint)
point = pointList[len(pointList)-1]
index += 1
else:
done = True
return pointList
class Direction(enum.Enum):
NONE = 1
UP = 2
DOWN = 3
LEFT = 4
RIGHT = 5
def getNextCell(point, direction):
if(direction == Direction.UP):
return Point(point.x-1, point.y)
elif(direction == Direction.DOWN):
return Point(point.x+1, point.y)
elif(direction == Direction.LEFT):
return Point(point.x, point.y-1)
elif(direction == Direction.RIGHT):
return Point(point.x, point.y+1)
point = Point(2, 4)
direction = Direction.UP
newList = setCells(point, direction)
print(point in newList)
which prints False. To investigate if this is correct it is useful to add some pretty printing to the class Point:
def __repr__(self):
return "Point(%s,%s)" % (self.x,self.y)
It is now possible to easily investigate the contents of the list:
>>> print(newList)
[Point(1,4)]
>>> print(point)
Point(2,4)
Since newList contains only one point which has a different x-coordinate it is obvious that point in newList should be false.
To better understand why newList does not contain point it is useful to give a simplified version of setCells:
def setCellsSimplified(point,direction):
return [getNextCell(point, direction)]
Explanation: Initially pointList is empty, so point not in pointList will be true regardless of the value of point. Thus newPoint is added to pointList and point is now equal to newPoint. Therefore, when the while-body runs again, point is in pointList and the second execution is the last execution of the while-body.
Since getNextCell always returns a new Point that differs in one coordinate from the object passed to it point and getNextCell(point,dir) are never equal (regardless of the direction) and therefore point in setCells(point,dir) is always false (which can be seen easily by looking at the simplified version setCellsSimplified).

I'm confused my how you are invoking this. Your function takes in self, list, and point. If this is a method of an object, and you want to see if the current object is in the list I would try something like this instead...
def isInList(self, list):
return self in list
That should give you an output similar to this...
>>> list = [Point(2,2), Point(3,3), Point(4,4)]
>>> x = Point(4,4)
>>> x.isInList(list)
True
>>> x = Point(4,5)
>>> x.isInList(list)
False

Related

I've got an object that is basically an int with some extra properties. Can I coerce it into an int when it's used as a list index?

Context: I'm making a game that happens in a maze made of square tiles and almost everything, from movement to attacks, involves directions, which are mostly used to index lists. Subtracting or adding to directions is an easy way to turn left or right, but I always have to check that they are still within bounds, and I would like to automate that by making a custom class.
Here is how I'm currently doing it:
global UP
UP = 0
global RIGHT
RIGHT = 1
global DOWN
DOWN = 2
global LEFT
LEFT = 3
And here is what I'd like to do:
class Direction:
number_of_directions=4
def __init__(self,direction):
self.direction = direction
def __int__(self):
return self.direction
def __add__(self,other): #Here other is supposed to be an int
return (self.direction + other)%number_of_directions
def __sub__(self,other): #Here other is supposed to be an int
return (self.direction - other)%number_of_directions
global UP
UP = Direction(0)
global LEFT
LEFT = Direction(1)
global DOWN
DOWN = Direction(2)
global RIGHT
RIGHT = Direction(3)
The only problem with that is that I am using UP, RIGHT, etc. as indexes, like I have a Tile that has a list of four Wall and I constantly call Tile.walls[direction] with direction being one of my four constants, and I don't want to have to specify Tile.walls[int(direction)] everytime.
Is there a way to have direction automatically coerced into an int whenever it's used for indexing?
you could use an IntEnum:
from enum import IntEnum
from numbers import Integral
class Direction(IntEnum):
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3
_NB_DIRECTIONS = 4
def __add__(self, other):
if isinstance(other, Integral):
return Direction((self.value + other) % Direction._NB_DIRECTIONS)
return NotImplemented
def __sub__(self, other):
if isinstance(other, Integral):
return Direction((self.value - other) % Direction._NB_DIRECTIONS)
return NotImplemented
those are subclasses of int and can be used e.g. as indices for lists:
lst = list(range(4))
print(lst[Direction.LEFT]) # -> 3
the examples you give work like this:
print(Direction.UP) # Direction.UP
print(Direction.UP + 1) # Direction.RIGHT
print(Direction.UP - 1) # Direction.LEFT
print(Direction.UP + 10) # Direction.DOWN
a = Direction.UP
a += 1
print(a) # Direction.RIGHT
print(Direction.UP) # Direction.UP
print(type(a)) # <enum 'Direction'>
b = 1
print(type(b)) # <class 'int'>
b += Direction.UP
print(b) # 1
print(type(b)) # <class 'int'>
print(Direction.DOWN - 1 == Direction.UP + 1) # True
lst = ["zero", "one", "two", "three"]
print(lst[Direction.DOWN]) # 'two'
print(lst[Direction.UP + 3]) # 'three'
print(lst[Direction.LEFT - 2]) # 'one'
Yes, simply define __index__(). For example:
class Direction:
def __init__(self, direction):
self.direction = direction
def __index__(self):
return self.direction
UP = Direction(0)
cardinals = ['north', 'east', 'south', 'west']
print(cardinals[UP]) # -> north
This also makes __int__ unnecessary since __index__ is used as a fallback.
print(int(UP)) # -> 0
P.S. For this answer, I'm ignoring any design considerations. Using an IntEnum might be a better solution, I'm not sure.
I got my code to work by making Direction a subclass of int.
Here is what my current code looks like:
global NB_DIRECTIONS
NB_DIRECTIONS = 4
(This part is a bit superfluous, just in case I want to adapt the game with, say, hexagons or triangles instead of squares later on. The real code starts now.)
class Direction(int):
directions = NB_DIRECTIONS
def __init__(self,direction):
self.direction = direction
def __add__(self,other):
if isinstance(other,int):
return Direction((self.direction+other)%self.directions)
return NotImplemented
def __radd__(self,other):
if isinstance(other,int):
return Direction((other+self.direction)%self.directions)
return NotImplemented
def __sub__(self,other):
if isinstance(other,int):
return Direction((self.direction-other)%self.directions)
return NotImplemented
def __rsub__(self,other):
return NotImplemented
def __eq__(self, other):
if isinstance(other,Direction):
return self.direction == other.direction
return NotImplemented
global UP
UP=Direction(0)
global RIGHT
RIGHT=Direction(1)
global DOWN
DOWN=Direction(2)
global LEFT
LEFT=Direction(3)
(I made the addition be between a Direction object and an int, not between two Direction object, because it makes more sens for what I'm doing, but that's irrelevant to the problem of indexing I was trying to solve.)
Let's look at my Direction's behavior:
>>> UP
0
>>> UP+1
1
>>> UP-1
3
>>> UP+10
2
>>> a=UP
>>> a+=1
>>> a
1
>>> UP
0
>>> type(a)
<class '__main__.Direction'>
>>> b=1
>>> type(b)
<class 'int'>
>>> b+=UP
>>> b
1
>>> UP
0
>>> type(b)
<class '__main__.Direction'>
>>> DOWN-1==UP+1
True
>>> lst=["zero","one","two","three"]
>>> lst[DOWN]
'two'
>>> lst[UP+3]
'three'
>>> lst[LEFT-2]
'one'
>>> type(RIGHT)
<class '__main__.Direction'>
TL;DR:
I made my class inherit from int, now it can be used as an index.

Apply class method to an object in another class in Python 2.7

I'm trying to create a code in Python 2.7 that represents a LineString and then move the LineString by the defined x, y values (in this case (-1, -1)).
I'm using two classes.
First is class Points that represents the single x, y of each line and second is class LineString where I'm first converting the tuple of x,y line points (p) to a list using the Point class.
What I'm stick with is how to apply the move function in class Points to LineString move.
In other words by using Points internally in the LineString class I should be able to use the move() implemented in the Point class instead of implementing it again in the Line String class.
I went through similar forums but could not find answer to my problem. So, I will be thankful for any advice.
from itertools import starmap
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, move_x, move_y):
self.x = self.x + move_x
self.y += move_y
class LineString(object):
def __init__(self, *args):
print 'These are the arguments as tuple of tuples:', args
self.points = [Point(*p) for p in args]
def move(self, move_x, move_y):
for p in self.points:
p.move() # This is the part I don't know how to implement
# the move method for each point p
def __getitem__(self, index):
return self.points[index]
if __name__ == '__main__':
lin1 = LineString((1, 1), (0, 2))
lin1.move(-1, -1) # Move by -1 and -1 for x and y respectively
assert lin1[0].y == 0 # Inspect the y value of the start point.
lin2 = LineString((1, 1), (1, 2), (2, 2))
lin2.move(-1, -1) # Move by -1 and -1 for x and y respectively
assert lin2[-1].x == 1 # Inspect the x value of the end point.
print 'Success! Line tests passed!'
You're overthinking this. Whatever arguments you pass to LineString.move have to be passed on to Point.move as well.
def move(self, move_x, move_y):
for p in self.points:
p.move(move_x, move_y)

python - Trouble calculating manhatan distance, TypeError

So I have a school project where we need to make a few classes for a GPS system. I'm having an issue figuring out the function dist(self,other): shown at the bottom of my code. Other definitions later in the project heavily rely on it, but i'm stumped at this point. The dist function calculates the Manhattan distance (x1-x2)+(y1-y2) of a location defined by instance variables x and y, and another location other which is given as a Tuple
class GPS_Location:
def __init__(self,x,y):
self.x=x
self.y=y
def __str__(self):
return '(%s,%s)' % (self.x,self.y)
def __repr__(self):
return 'GPS_Location(%s,%s)' % (self.x,self.y)
def __eq__(self,other):
self.other = other
if (self.x,self.y) == other:
return True
else:
return False
def dist(self,other):
self.other = other
return abs(self.x - (other[0])) + abs(self.y - (other[1])) #TypeError
When testing the code, I keep getting "TypeError: 'GPS_Location' object is not iterable". I have tried so many tweaks, and I just can't figure out what i'm doing wrong.
Any help would be greatly appreciated!
Ensure that line 8 is indented by 4 spaces like the rest of the methods.
There doesn't seem to be any reason to assign other to self.other in __eq__() and dist().
The only other issue you might be having could be related to how you are calling these methods (you mentioned that the argument other is just a tuple), this works:
x = GPS_Location(1, 1)
x == (1, 1)
# True
x == (2, 2)
# False
x.dist((1, 1))
# 0
x.dist((2, 2))
# 2
If you in fact need to pass a second GPS_Location as the other argument to dist, then it needs to be updated as follows:
def dist(self, other):
return abs(self.x - other.x) + abs(self.y - other.y)
Call it like so:
x = GPS_Location(1, 1)
y = GPS_Location(2, 2)
x.dist(y)
# 2

line 60, in make_tuple return tuple(l) TypeError: iter() returned non-iterator of type 'Vector'

I am new to Vectors and making classes. I am trying to construct my own vector class but when i pass it through my code which is:
position += heading*distance_moved
where position and heading are both vectors. heading is normalized. my goal is to repeat my code until position = destination.
What is wrong with this class?
import math
class Vector(object):
#defaults are set at 0.0 for x and y
def __init__(self, x=0.0, y=0.0):
self.x = x
self.y = y
#allows us to return a string for print
def __str__(self):
return "(%s, %s)"%(self.x, self.y)
# from_points generates a vector between 2 pairs of (x,y) coordinates
#classmethod
def from_points(cls, P1, P2):
return cls(P2[0] - P1[0], P2[1] - P1[1])
#calculate magnitude(distance of the line from points a to points b
def get_magnitude(self):
return math.sqrt(self.x**2+self.y**2)
#normalizes the vector (divides it by a magnitude and finds the direction)
def normalize(self):
magnitude = self.get_magnitude()
self.x/= magnitude
self.y/= magnitude
#adds two vectors and returns the results(a new line from start of line ab to end of line bc)
def __add__(self, rhs):
return Vector(self.x +rhs.x, self.y+rhs.y)
#subtracts two vectors
def __sub__(self, rhs):
return Vector(self.x - rhs.x, self.y-rhs.y)
#negates or returns a vector back in the opposite direction
def __neg__(self):
return Vector(-self.x, -self.y)
#multiply the vector (scales its size) multiplying by negative reverses the direction
def __mul__(self, scalar):
return Vector(self.x*scalar, self.y*scalar)
#divides the vector (scales its size down)
def __div__(self, scalar):
return Vector(self.x/scalar, self.y/scalar)
#iterator
def __iter__(self):
return self
#next
def next(self):
self.current += 1
return self.current - 1
#turns a list into a tuple
def make_tuple(l):
return tuple(l)
I guess you are using python 3.x, because I've got a similar error.
I'm also new on making class, but it would be nice to share what I learned :)
In 3.x, use __next__() instead of next() in the definition of classes.
The error haven't occurred after I renamed it in your code, but I got another problem, "'Vector' object has no attribute 'current'" :)
I think it might be better for you to understand iterators (and class?) more.
A simplest example is:
class Count:
def __init__(self, n):
self.max = n
def __iter__(self):
self.count = 0
return self
def __next__(self):
if self.count == self.max:
raise StopIteration
self.count += 1
return self.count - 1
if __name__ == '__main__':
c = Count(4)
for i in c:
print(i, end = ',')
and the outputs are 0,1,2,3,.
With a vector class, I want to iterate the components of the vector. So:
def __iter__(self):
self.count = 0
self.list = [self.x, self.y, self.z] # for three dimension
return self
def __next__(self):
if self.count == len(self.list):
raise StopIteration
self.count += 1
return self.list[self.count - 1]
and the iterator outputs the sequence x, y, z.
Note that the most important feature of iterators is to give the sequence step by step without creating whole list. So it is not very good idea to make self.list if the sequence will be very long.
More details here: python tutorial
The first argument that's being passed into make_tuple is your Vector instance (it's the same self argument that you put everywhere).
You have to pass in what you want to turn into a tuple, which is probably your x and y coordinates:
def make_tuple(self):
return (self.x, self.y)

Add method that works with either a Point Object or a tuple

One of my exercises says to write an add method for Points that works with either a Point object or a tuple:
If the second operand is a Point, the method should return a new Point whose x coordinate is the sum of the x coordinates of the operands, and likewise for the y coordinates.
If the second operand is a tuple, the method should add the first element of the tuple to the x coordinate and the second element to the y coordinate, and return a new Point with the result.
This how far I got and I'm not sure if the tuple portion of my code is accurate. Can someone shed some light how I would call this program for the tuple portion. I think I nailed the first part.
Here is my code:
Class Point():
def__add__(self,other):
if isinstance(other,Point):
return self.add_point(other)
else:
return self.print_point(other)
def add_point(self,other):
totalx = self.x + other.x
totaly = self.y + other.y
total = ('%d, %d') % (totalx, totaly)
return total
def print_point(self):
print ('%d, %d) % (self.x, self.y)
blank = Point()
blank.x = 3
blank.y = 5
blank1 = Point()
blank1.x = 5
blank1.y = 6
That's what I've built so far and I'm not sure how to actually run this with the tuple part. I know if it did blank + blank1 the if portion would run and call the add_point function but how do I initiate the tuple. I'm not sure if I wrote this correctly... please assist.
You can simply derive your class from the tuple (or just implement __getitem__).
class Point(tuple):
def __new__(cls, x, y):
return tuple.__new__(cls, (x, y))
def __add__(self, other):
return Point(self[0] + other[0], self[1] + other[1])
def __repr__(self):
return 'Point({0}, {1})'.format(self[0], self[1])
p = Point(1, 1)
print p + Point(5, 5) # Point(6, 6)
print p + (5, 5) # Point(6, 6)
Alternatively, if you want to be able to use point.x and point.y syntax, you could implement the following:
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
if isinstance(other, Point):
return Point(self.x + other.x, self.y + other.y)
elif isinstance(other, tuple):
return Point(self.x + other[0], self.y + other[1])
else:
raise TypeError("unsupported operand type(s) for +: 'Point' and '{0}'".format(type(other)))
def __repr__(self):
return u'Point ({0}, {1})'.format(self.x, self.y) #Remove the u if you're using Python 3

Categories

Resources