If you will always have two parts, you could use complex literals to represent the pair of values (so x
would be the real part, and y
the imaginary part):
>>> x_y = 5 + 0j
>>> x_y += 1 + 8j
>>> x_y.real, x_y.imag
(6.0, 8.0)
Obviously this looks a little complex (!) when you're only doing one operation, but if you're using lots of paired values it will work well. However, it is considered a hack and makes your code less readable (people may wonder what's doing on with .real
and .imag
).
A better alternative is to build your own numeric type to hold the related values. For example:
>>> from collections import namedtuple
>>> class XY(namedtuple('XY', 'x y')):
def __repr__(self):
return 'XY({0.x!r}, {0.y!r})'.format(self)
def __add__(self, other):
return XY(self.x + other.x, self.y + other.y)
>>> xy = XY(5, 0)
>>> xy += XY(1, 8)
>>> xy
XY(6, 8)
This is more readable and more flexible for adaptation to larger groups of numbers, whereas complex numbers can only hold two values. With minor tweaks, XY.__add__
could also accept any iterable of length two, so that e.g. xy += (1, 8)
would also work.
In terms of why your original attempt doesn't work, note that the augmented assignment documentation states that (emphasis mine):
An augmented assignment evaluates the target (which, unlike normal
assignment statements, cannot be an unpacking) and the expression
list, performs the binary operation specific to the type of assignment
on the two operands, and assigns the result to the original target.
The target is only evaluated once.