I've got a small problem which in itself isn't a big deal but is bugging me none the less. Consider the code below.
import pygame
class vector:
def __init__(s, x, y):
s.x = int(x)
s.y = int(y)
s.t = (s.x, s.y)
def __add__(s, n):
return vector(s.x + n[0], s.y + n[1])
size = vector(10, 10)
pygame.Surface((size + (5, 5)).t)
When passing vector as a parameter to pygame.Surface I have to use the 't' attribute to access the tuple stored in 'size'.
Is there a way to have it simply like this?
pygame.Surface(size + (5, 5))
Is there a magic method that returns a value if no attribute or method is referenced?
In pygame you can define a vector like this, v = pygame.math.vector2(10, 10) and then pass that vector to a surfaces blit function like this, someSurface.blit(sprite, v) and there's no need to reference a method or attribute to get the value so it does seem possible, though I guess it's perfectly plausible that the blit function can handle a vector2 as an argument?
Thank you for you time.
Implement __len__ and __getitem__:
class vector:
def __init__(s, x, y):
s.x = int(x)
s.y = int(y)
s.t = (s.x, s.y)
def __add__(s, n):
return vector(s.x + n[0], s.y + n[1])
def __len__(s):
return 2
def __getitem__(s, i):
return [s.x, s.y][i]
I have a custom object like this:
class MyObject:
def __init__(self, x, y):
self.x = x
self.y = y
I want it to work with sets according to the rule: if objects have the same x they are equal.
s = set()
s.add(MyObject(1, 2))
print(MyObject(1, 3) in s) # It is False. I want it to be True, because `x = 1` for both.
Is there a magic method I could implement in MyObject to reach my purpose?
__eq__(self, other)
__hash__(self)
See https://hynek.me/articles/hashes-and-equality/ for more
I have 2 sets, each containing objects of the following class:
class pointInfo:
x = 0
y = 0
steps = 0
I want to find the intersection of the two sets, but only on the x and y values.
something like:
def findIntersections(pointInfoSet1, pointInfoSetwire2):
return [pointInfo for pointInfo in pointInfoSet1 if pointInfo.x, pointInfo.y in pointInfoSet2]
I know if you have 2 sets in python you can just do set1.intersection(set2), but that wont work in this case because I just want to find where a certain subset of the object attributes are the same, not identical objects. Thanks in advance!
Here's a solution that makes Point objects that are Hashable on their x and y attributes:
class Point:
def __init__(self, x=0, y=0, step=0):
self.x = x
self.y = y
self.step = step
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return (self.x, self.y) == (other.x, other.y)
def __hash__(self):
return hash((self.x, self.y))
def __repr__(self):
return "Point(x={0.x}, y={0.y}, step={0.step})".format(self)
We can then put them in sets and get intersections naturally:
{Point(1, 1, 1), Point(2, 2)} & {Point(1, 1, 2)}
# {Point(x=1, y=1, step=2)}
Assuming no wire crosses itself, a better solution might be to iterate through both wires, maintaining a dict of points to steps, and outputting the sum of the steps at each intersection:
from itertools import chain
def stepsToIntersections(wire1, wire2):
seen = {}
for point in chain(wire1, wire2):
if point in seen:
yield point.step + seen[point]
else:
seen[point] = point.step
closest = min(stepsToIntersections(wire1, wire2))
The problem in the code is that Vector.numerical_vector is a list of copies of floats, but I need it to be list of references, so when Vector.vector[n].value is changed, Vector.numerical_vector[n] is changed to the same value as well.
Thanks for help in advance!
class Var:
def __init__(self, val):
self.value = float(val)
def __float__(self):
return self.value
class Vector:
def __init__(self, vector):
self.vector = vector
self.numerical_vector = [float(x) for x in vector]
vars = [Var(i) for i in range(5)]
vector = Vector(vars)
There's no way to do that in python. What you could do is make numerical_vector an object that, when accessed, returns the float value of the corresponding vector item. Eg
class VectorWrapper:
def __init__(self, vector):
self.vector = vector
def __getitem__(self, i):
return float(self.vector[i])
and set self.numerical_vector = VectorWrapper(self.vector)
If you have to return a float representation when self.numerical_vector[i] is referenced,
You might want to employ a property for that.
class Vector:
def __init__(self, vector):
self.vector = vector
#property
def numerical_vector(self):
return [x.value for x in self.vector]
Now vector.numerical_vector will always be synchronized. A drawback of this method is that it is recomputed each time you access it, some it may not be adapted to your specific application.
If performance is an issue, you could add __getitem__ and __setitem__ methods to Vector as follows:
class Vector:
def __init__(self, vector):
self.vector = vector
self.numerical_vector = [float(x) for x in vector]
def __getitem__(self, i):
return self.vector[i]
def __setitem__(self, i, val):
self.vector[i] = val
self.numerical_vector[i] = float(val)
In that case, if you set vector_instance[i], then vector_instance.numerical_vector[i] will be also modified. But if you want to modify vector_instance.vector[i] directly, then synchronicity will be broken.
Depending on the use case, you can use either of the two approaches. Both have limitations but I don't think much more can be done.
I am trying to sort the Points based on the X and Y properties of the point object.A small example below to explain my process:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return '[{},{},{}]'.format(self.x, self.y, self.z)
#point instances
p1,p2,p3 = Point(7,85,5), Point(56,16,20), Point(24,3,30)
point_list = [p1,p2,p3]
def get_X(point):
return point.x
def get_Y(point):
return point.y
sorted_points = sorted(point_list, key = get_X)
# print(sorted_points) // [[7,85,5], [24,3,30], [56,16,20]]
sorted_points = sorted(sorted(point_list, key = get_X), key = get_Y)
# print(sorted_points) // [[24,3,30], [56,16,20], [7,85,5]]
But I need an output like this sorting X first keep them in same order and then sort Y
[[7,3,5], [24,16,30], [56,85,20]]
I think I am trying to exchange the properties of each instances by achieving the above, But I don't know how to do that.
Tuples will naturally sort in the way you want. You can simplify things by adding a __lt__() function to your class. Sorted will use this function to compare. Then you can depend on the natural sorting order of tuples easily with something like this:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return '[{},{},{}]'.format(self.x, self.y, self.z)
def __iter__(self):
return iter((self.x, self.y, self.z))
def __lt__(self, other):
return (self.x, self.y, self.z) < (other.x, other.y, other.z)
#point instances
point_list = [Point(7,85,5), Point(56,16,20), Point(24,3,30), Point(7, 20, 0), Point(56,16,15)]
sorted(point_list)
# --> [[7,20,0], [7,85,5], [24,3,30], [56,16,15], [56,16,20]]
EDIT: Create new points
To create new points by combining the sorted elements of each point individually you can unzip your points, sort them and then zip them again. The nicest way to do this is to add an __iter__() function to your class to make it iterable so it can support zip. I've done this in the code above. This will allow you to do this:
point_list = [Point(7,85,5), Point(56,16,20), Point(24,3,30), Point(7, 20, 0), Point(56,16,15)]
newTuples = list(zip(*[sorted(l) for l in zip(*point_list)]))
sortedPoints = [Point(*p) for p in newTuples ]
#sortedPoint => [[7,3,0], [7,16,5], [24,16,15], [56,20,20], [56,85,30]]
This also sorts the z values, but it's easy enough to change that if you need it for some reason.
By placing the key elements in tuples in the order you want them sorted (primary value first, secondary value second), the ordering method of tuples will automatically perform in the way you are hoping to achieve.
All you need to change is that your value for key should be set to key=get_XY, where get_XY returns a tuple of x and y coordinates:
def get_XY(point):
return point.x, point.y