I want the summation of 3 different objects like:
`2 3 4
2 3 4
2 3 4
6 9 12`the summation must be like this
And tried to do this
`
class mymath:
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z
def __add__(self,other):
return self.x+other.x, self.y+other.y, self.z+other.z
x=mymath(2,7,6)
y=mymath(4,3,8)
z=mymath(2,4,6)
print(x+y+z)
You are returning a tuple, which doesn't have the __add__() method overloaded. You should return a mymath object instead:
class mymath:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
return mymath(self.x + other.x, self.y + other.y, self.z + other.z)
def __str__(self):
return "({}, {}, {})".format(self.x, self.y, self.z)
x = mymath(2, 7, 6)
y = mymath(4, 3, 8)
z = mymath(2, 4, 6)
print(x + y + z) # Result: (8, 14, 20)
Edit: clarification of the solution added after comment
Each + sign translates to an __add__() call. In your example, the operation x + y + z is actually performing two calls to __add__(): x.__add__(y).__add__(z).
Adding parentheses to the expression may help: x + y + z actually translates to (x.__add__(y)).__add__(z).
The problem happens in the second call to __add__(), since your method is returning self.x + other.x, self.y + other.y, self.z + other.z which is the tuple (self.x + other.x, self.y + other.y, self.z + other.z) (you can omit the parentheses in your code, and it's more pythonic, but it's equivalent and it's actually a tuple).
A tuple is a fixed-length list of elements and it's a basic class of python language. You can read more about it here.
The result of x.__add__(y) is the summation you would expect from x + y, but of type tuple. In the example, (6, 10, 14) == (2 + 4, 7 + 3, 6 + 8)
You can check this running your code but printing just x + y
print(x + y) # Prints (6, 10, 14)
And also:
print(type(x + y)) # Prints <class 'tuple'>
The second addition, though, fails, because the result of the first one is a tuple and not a mymath object. So (x + y) + z actually is calling the __add__() method of the tuple, which exists but has other meaning than the one you want. Therefore, you are obtaining the error TypeError: can only concatenate tuple (not "mymath") to tuple
Note that adding two tuples is just appending them and not adding the coordinates element-wise: (1, 2, 3) + (4, 5, 6) ==> (1, 2, 3, 4, 5, 6)
The solution to this problem is to return a mymath object as the result of the __add__() operation, allowing to concatenate more than one addition operation.
I added the __str__() method to your class because otherwise the print is just showing a default representation of the class like <__main__.mymath object at 0x7f8654657390>.
Related
This question already has answers here:
"Enabling" comparison for classes [duplicate]
(4 answers)
Closed 10 months ago.
I have this code:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
return Point((self.x ** 2) + (other.x ** 2), (self.y ** 2) + (other.y ** 2), (self.z ** 2) + (other.z ** 2))
def __str__(self):
return f'x: {self.x}, y: {self.y}, z: {self.z}'
pt1 = Point(3, 4, -5)
pt2 = Point(-4, 1, 3)
pt3 = pt1 + pt2
print(pt1 == pt2)
Now I want to change == in the last line to > or <, but this error was raised:
TypeError: '>' not supported between instances of 'Point' and 'Point'
These are the so-called "rich comparison" methods.
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
The correspondence between operator symbols and method names is as follows:
x<y calls x.__lt__(y)
x<=y calls x.__le__(y)
x==y calls x.__eq__(y)
x!=y calls x.__ne__(y)
x>y calls x.__gt__(y)
x>=y calls x.__ge__(y).
Reference
docs.python/datamodel
I am having trouble referring to a class via a list and then comparing the integers for a required list output.
some examples of correct referencing would be appreciated or if I'm trying to do something python cant do.
see example code below:
'''
#creating class
class class1:
def __init__(self, m, x, y, z):
self.m = m
self.x = x #int
self.y = y #int
self.z = z #int
#creating list
list = []
compare = []
# appending instances to list
list.append( class1( m, x, y, z) )
list.append( class1( m, x, y, z) )
list.append( class1( m, x, y, z) )
#comparison values
a=#int
b=#int
c=#int
#boolean
comparison=True
for obj in list:
if obj.x > a:
comparison=False
if obj.y > b:
comparison=False
if obj.z > c:
comparison=False
if comparison:
compare.append (obj.m)
else:
print ()
print (compare)
'''
I went ahead and tried to clean up the code for you. I think I got what you were trying to do with the logic block at the very end. Hopefully this does what you wanted. The first Class1 object appended to mylist is instantiated with all zeros which will cause all the comparisons to return false and therefore obj.m -> 0 will append to the compare list
class Class1:
def __init__(self, m, x, y, z):
self.m = m
self.x = x # int
self.y = y # int
self.z = z # int
# creating list
mylist = []
compare = []
# appending instances to list
mylist.append(Class1(0, 0, 0, 0))
mylist.append(Class1(2, 3, 4, 5))
mylist.append(Class1(3, 4, 5, 6))
# comparison values
a = 1
b = 2
c = 3
# boolean
# I cleaned up the logic. Hopefully it's easier to understand
for obj in mylist:
comparison = False
if obj.x > a or obj.y > b or obj.z > c:
comparison = True
if not comparison:
compare.append(obj.m)
print("All comparisons were false")
else:
print("At least one comparsion is true")
print(compare)
In Python, I've seen two variable values swapped using this syntax:
left, right = right, left
Is this considered the standard way to swap two variable values or is there some other means by which two variables are by convention most usually swapped?
Python evaluates expressions from left to right. Notice that while
evaluating an assignment, the right-hand side is evaluated before the
left-hand side.
Python docs: Evaluation order
That means the following for the expression a,b = b,a :
The right-hand side b,a is evaluated, that is to say, a tuple of two elements is created in the memory. The two elements are the objects designated by the identifiers b and a, that were existing before the instruction is encountered during the execution of the program.
Just after the creation of this tuple, no assignment of this tuple object has still been made, but it doesn't matter, Python internally knows where it is.
Then, the left-hand side is evaluated, that is to say, the tuple is assigned to the left-hand side.
As the left-hand side is composed of two identifiers, the tuple is unpacked in order that the first identifier a be assigned to the first element of the tuple (which is the object that was formerly b before the swap because it had name b)
and the second identifier b is assigned to the second element of the tuple (which is the object that was formerly a before the swap because its identifiers was a)
This mechanism has effectively swapped the objects assigned to the identifiers a and b
So, to answer your question: YES, it's the standard way to swap two identifiers on two objects.
By the way, the objects are not variables, they are objects.
That is the standard way to swap two variables, yes.
I know three ways to swap variables, but a, b = b, a is the simplest. There is
XOR (for integers)
x = x ^ y
y = y ^ x
x = x ^ y
Or concisely,
x ^= y
y ^= x
x ^= y
Temporary variable
w = x
x = y
y = w
del w
Tuple swap
x, y = y, x
I would not say it is a standard way to swap because it will cause some unexpected errors.
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
nums[i] will be modified first and then affect the second variable nums[nums[i] - 1].
Does not work for multidimensional arrays, because references are used here.
import numpy as np
# swaps
data = np.random.random(2)
print(data)
data[0], data[1] = data[1], data[0]
print(data)
# does not swap
data = np.random.random((2, 2))
print(data)
data[0], data[1] = data[1], data[0]
print(data)
See also Swap slices of Numpy arrays
To get around the problems explained by eyquem, you could use the copy module to return a tuple containing (reversed) copies of the values, via a function:
from copy import copy
def swapper(x, y):
return (copy(y), copy(x))
Same function as a lambda:
swapper = lambda x, y: (copy(y), copy(x))
Then, assign those to the desired names, like this:
x, y = swapper(y, x)
NOTE: if you wanted to you could import/use deepcopy instead of copy.
That syntax is a standard way to swap variables. However, we need to be careful of the order when dealing with elements that are modified and then used in subsequent storage elements of the swap.
Using arrays with a direct index is fine. For example:
def swap_indexes(A, i1, i2):
A[i1], A[i2] = A[i2], A[i1]
print('A[i1]=', A[i1], 'A[i2]=', A[i2])
return A
A = [0, 1, 2, 3, 4]
print('For A=', A)
print('swap indexes 1, 3:', swap_indexes(A, 1, 3))
Gives us:
('For A=', [0, 1, 2, 3, 4])
('A[i1]=', 3, 'A[i2]=', 1)
('swap indexes 1, 3:', [0, 3, 2, 1, 4])
However, if we change the left first element and use it in the left second element as an index, this causes a bad swap.
def good_swap(P, i2):
j = P[i2]
#Below is correct, because P[i2] is modified after it is used in P[P[i2]]
print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
P[P[i2]], P[i2] = P[i2], P[P[i2]]
print('Good swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
return P
def bad_swap(P, i2):
j = P[i2]
#Below is wrong, because P[i2] is modified and then used in P[P[i2]]
print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
P[i2], P[P[i2]] = P[P[i2]], P[i2]
print('Bad swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
return P
P = [1, 2, 3, 4, 5]
print('For P=', P)
print('good swap with index 2:', good_swap(P, 2))
print('------')
P = [1, 2, 3, 4, 5]
print('bad swap with index 2:', bad_swap(P, 2))
('For P=', [1, 2, 3, 4, 5])
('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Good swap: After P[i2]=', 4, 'P[P[i2]]=', 3)
('good swap with index 2:', [1, 2, 4, 3, 5])
('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Bad swap: After P[i2]=', 4, 'P[P[i2]]=', 4)
('bad swap with index 2:', [1, 2, 4, 4, 3])
The bad swap is incorrect because P[i2] is 3 and we expect P[P[i2]] to be P[3]. However, P[i2] is changed to 4 first, so the subsequent P[P[i2]] becomes P[4], which overwrites the 4th element rather than the 3rd element.
The above scenario is used in permutations. A simpler good swap and bad swap would be:
#good swap:
P[j], j = j, P[j]
#bad swap:
j, P[j] = P[j], j
You can combine tuple and XOR swaps: x, y = x ^ x ^ y, x ^ y ^ y
x, y = 10, 20
print('Before swapping: x = %s, y = %s '%(x,y))
x, y = x ^ x ^ y, x ^ y ^ y
print('After swapping: x = %s, y = %s '%(x,y))
or
x, y = 10, 20
print('Before swapping: x = %s, y = %s '%(x,y))
print('After swapping: x = %s, y = %s '%(x ^ x ^ y, x ^ y ^ y))
Using lambda:
x, y = 10, 20
print('Before swapping: x = %s, y = %s' % (x, y))
swapper = lambda x, y : ((x ^ x ^ y), (x ^ y ^ y))
print('After swapping: x = %s, y = %s ' % swapper(x, y))
Output:
Before swapping: x = 10 , y = 20
After swapping: x = 20 , y = 10
What is the best way of implementing an efficient Vector / Point class (or even better: is there one already), that can be used both in Python 2.7+ and 3.x?
I've found the blender-mathutils, but they seem to only support Python 3.x. Then there's this Vector class, that uses numpy, but it's only a 3D vector. Using a list for a Vector like kivy's vector class (sourcecode) that has static attributes (x and y) seems weird too. (There are all these list-methods.)
At the moment I'm using a class that extends namedtuple (as you can see below), but this has the disadvantage of not being able to change the coordinates. I think this can become a performance problem, when thousands of objects are moving and a new (vector) tuple is created everytime. (right?)
class Vector2D(namedtuple('Vector2D', ('x', 'y'))):
__slots__ = ()
def __abs__(self):
return type(self)(abs(self.x), abs(self.y))
def __int__(self):
return type(self)(int(self.x), int(self.y))
def __add__(self, other):
return type(self)(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return type(self)(self.x - other.x, self.y - other.y)
def __mul__(self, other):
return type(self)(self.x * other, self.y * other)
def __div__(self, other):
return type(self)(self.x / other, self.y / other)
def dot_product(self, other):
return self.x * other.x + self.y * other.y
def distance_to(self, other):
""" uses the Euclidean norm to calculate the distance """
return hypot((self.x - other.x), (self.y - other.y))
Edit: I did some testing and it seems that using numpy.array or numpy.ndarray as a vector is too slow. (For example getting an item takes almost twice as long, not to mention creating an array. I think it's more optimized for doing calculations on a large number of items.)
So, I'm looking more for a lightweight vector class with a fixed number of fields (in my case just x and y) that can be used for games. (I don't want to re-invent the wheel if there's already a well-tested one.)
Yeah, there is a vector class: it's in the de facto standard NumPy module. You create vectors like so:
>>> v = numpy.array([1, 10, 123])
>>> 2*v
array([ 2, 20, 246])
>>> u = numpy.array([1, 1, 1])
>>> v-u
array([ 0, 9, 122])
NumPy is very rich and gives you access to fast array operations: dot product (numpy.dot()), norm (numpy.linalg.norm()), etc.
The vector class in numpy in terms of linear algebra would probably be the numpy.matrix which is a subclass of numpy.ndarray. It's not cleaner per se but it makes your code cleaner because algebraic operations are assumed instead of elementwise.
In [77]: a = np.array([1,2])
In [78]: b = np.array([3,3])
In [79]: a*b
Out[79]: array([3, 6])
In [80]: np.dot(a,b)
Out[80]: 9
In [81]: np.outer(a,b)
Out[81]:
array([[3, 3],
[6, 6]])
In [82]: a = np.matrix(a).T
In [83]: b = np.matrix(b)
In [84]: b*a
Out[84]: matrix([[9]])
In [85]: a*b
Out[85]:
matrix([[3, 3],
[6, 6]])
If you want to create your own, base it on one of these, for example:
class v2d(np.ndarray):
def __abs__(self):
return np.linalg.norm(self)
def dist(self,other):
return np.linalg.norm(self-other)
def dot(self, other):
return np.dot(self, other)
# and so on
Which in the simplest case you can just make by viewing an ndarray as your new class:
In [63]: a = np.array([1,2]).view(v2d)
In [64]: b = np.array([3,3]).view(v2d)
In [65]: a
Out[65]: v2d([1, 2])
In [66]: abs(b)
Out[66]: 4.2426406871192848
In [67]: a - b
Out[67]: v2d([-2, -1])
In [68]: a*b
Out[68]: v2d([3, 6])
In [69]: a*3
Out[69]: v2d([3, 6])
In [70]: a.dist(b)
Out[70]: 2.2360679774997898
In [71]: b.dist(a)
Out[71]: 2.2360679774997898
In [72]: a.dot(b)
Out[72]: 9
Here is more information on subclassing the ndarray.
I needed a quick solution as well so I just wrapped numpy's array into my own. You'll notice some design decisions which can be changed to fit your own needs (like defaults).
If you'd like to use it: https://gist.github.com/eigencoder/c029d7557e1f0828aec5
import numpy as np
class Point(np.ndarray):
"""
n-dimensional point used for locations.
inherits +, -, * (as dot-product)
> p1 = Point([1, 2])
> p2 = Point([4, 5])
> p1 + p2
Point([5, 7])
See ``test()`` for more usage.
"""
def __new__(cls, input_array=(0, 0)):
"""
:param cls:
:param input_array: Defaults to 2d origin
"""
obj = np.asarray(input_array).view(cls)
return obj
#property
def x(self):
return self[0]
#property
def y(self):
return self[1]
#property
def z(self):
"""
:return: 3rd dimension element. 0 if not defined
"""
try:
return self[2]
except IndexError:
return 0
def __eq__(self, other):
return np.array_equal(self, other)
def __ne__(self, other):
return not np.array_equal(self, other)
def __iter__(self):
for x in np.nditer(self):
yield x.item()
def dist(self, other):
"""
Both points must have the same dimensions
:return: Euclidean distance
"""
return np.linalg.norm(self - other)
def test():
v1 = Point([1, 2, 3])
v2 = Point([4, 5, 7])
v3 = Point([4, ])
sum12 = Point([5, 7, 10])
dot12 = Point([4, 10, 21])
# Access
assert v2.x == 4
assert v2.y == 5
assert v2.z == 7
assert v3.z == 0
assert Point().x == 0
assert v2[0] == 4
assert v1[-1] == 3 # Not needed but inherited
assert [x for x in v2] == [4, 5, 7], "Iteration should return all elements"
# Operations
assert v1 + v2 == sum12
assert v1 * v2 == dot12
assert v1.dist(v2) ** 2 == 34
assert v1 != v2
assert v2.size == 3, "v2 should be a 3d point"
print "pass"
if __name__ == "__main__":
test()
In a graphical program I'm writing using pygame I use a tuple representing a coordinate like this: (50, 50).
Sometimes, I call a function which returns another tuple such as (3, -5), which represents the change in coordinate.
What is the best way to add the change value to the coordinate value. It would be nice if I could do something like coordinate += change, but it appears that would simply concatenate the two tuples to something like (50, 50, 3, -5). Rather than adding the 1st value to the 1st value and the 2nd to the 2nd, and returning a resulting tuple.
Until now I've been using this rather tiresome method:
coord = (coord[0] + change[0], coord[1] + change[1])
What is a better, more concise method to add together the values of two tuples of the same length. It seems especially important to know how to do it if the tuples are of an arbitrary length or a particularly long length that would make the previous method even more tiresome.
Well, one way would be
coord = tuple(sum(x) for x in zip(coord, change))
If you are doing a lot of math, you may want to investigate using NumPy, which has much more powerful array support and better performance.
List comprehension is probably more readable, but here's another way:
>>> a = (1,2)
>>> b = (3,4)
>>> tuple(map(sum,zip(a,b)))
(4,6)
As John Y mentions, this is pretty easy using numpy.
import numpy as np
x1 = (0,3)
x2 = (4,2)
tuple(np.add(x1,x2))
This is a work in progress as I am learning Python myself. Can we use classes here, could simplify some operations later. I propose to use a coord class to store the coordinates. It would override add and sub so you could do addition and subtraction by simply using operators + and -. You could get the tuple representation with a function built into it.
Class
class coord(object):
def __init__(self,x,y):
self.x = x
self.y = y
def __add__(self,c):
return coord(self.x + c.x, self.y + c.y)
def __sub__(self,c):
return coord(self.x - c.x, self.y - c.y)
def __eq__(self,c): #compares two coords
return self.x == c.x and self.y == c.y
def t(self): #return a tuple representation.
return (self.x,self.y)
Usage
c1 = coord(4,3) #init coords
c2 = coord(3,4)
c3 = c1 + c2 #summing two coordinates. calls the overload __add__
print c3.t() #prints (7, 7)
c3 = c3 - c1
print c3.t() #prints (3, 4)
print c3 == c2 #prints True
you could improve coord to extend other operators as well (less than, greater than ..).
In this version after doing your calculations you can call the pygame methods expecting tuples by just saying coord.t(). There might be a better way than have a function to return the tuple form though.
To get your "+" and "+=" behaviour you can define your own class and implement the __add__() method. The following is an incomplete sample:
# T.py
class T(object):
def __init__(self, *args):
self._t = args
def __add__(self, other):
return T(*([sum(x) for x in zip(self._t, other._t)]))
def __str__(self):
return str(self._t)
def __repr__(self):
return repr(self._t)
>>> from T import T
>>> a = T(50, 50)
>>> b = T(3, -5)
>>> a
(50, 50)
>>> b
(3, -5)
>>> a+b
(53, 45)
>>> a+=b
>>> a
(53, 45)
>>> a = T(50, 50, 50)
>>> b = T(10, -10, 10)
>>> a+b
(60, 40, 60)
>>> a+b+b
(70, 30, 70)
EDIT: I've found a better way...
Define class T as a subclass of tuple and override the __new__ and __add__ methods. This provides the same interface as class tuple (but with different behaviour for __add__), so instances of class T can be passed to anything that expects a tuple.
class T(tuple):
def __new__(cls, *args):
return tuple.__new__(cls, args)
def __add__(self, other):
return T(*([sum(x) for x in zip(self, other)]))
def __sub__(self, other):
return self.__add__(-i for i in other)
>>> a = T(50, 50)
>>> b = T(3, -5)
>>> a
(50, 50)
>>> b
(3, -5)
>>> a+b
(53, 45)
>>> a+=b
>>> a
(53, 45)
>>> a = T(50, 50, 50)
>>> b = T(10, -10, 10)
>>> a+b
(60, 40, 60)
>>> a+b+b
(70, 30, 70)
>>>
>>> c = a + b
>>> c[0]
60
>>> c[-1]
60
>>> for x in c:
... print x
...
60
40
60
My two cents, hope this helps
>>> coord = (50, 50)
>>> change = (3, -5)
>>> tuple(sum(item) for item in zip(coord, change))
(53, 45)