Skip to content

Instantly share code, notes, and snippets.

@pyrtsa
Created April 5, 2010 13:03
Show Gist options
  • Save pyrtsa/356316 to your computer and use it in GitHub Desktop.
Save pyrtsa/356316 to your computer and use it in GitHub Desktop.
class vec(tuple)
class vec(tuple):
"""
Tuples that behave less like containers, and more like vectors.
>>> 10 * vec(1,2,3) + 1
(11, 21, 31)
All basic operators behave component-wise, and binary operators broadcast
when given a non-iterable operand. Other than that, binary operators require
both operands to be of the same length.
>>> vec(xrange(4)) + 1
(1, 2, 3, 4)
Basic tuple concatenation by operator '+' is overridden, but there is
another way to concatenate vec's: put multiple tokens in the vec
constructor. The constructor flattens all the way down any nested iterables
given.
>>> vec(1)
(1,)
>>> vec(1,2,3)
(1, 2, 3)
>>> vec((1,True))
(1, True)
>>> vec(0, (1, 2), 2 + vec(1, 2, 3)) # concatenating constructor
(0, 1, 2, 3, 4, 5)
Class vec is a subclass of tuple, but if a tuple is needed (to cancel the
operator overloads), the vec object can be "cast" back to tuple by
constructing a tuple again:
>>> x = vec(1,2,3)
>>> t = tuple(x)
>>> type(x), type(t)
(<type 'vec'>, <type 'tuple'>)
"""
def __new__(cls, *args): return tuple.__new__(cls, flatten(args))
def __add__ (self, other): return vec(a+b for a,b in self._op(other))
def __sub__ (self, other): return vec(a-b for a,b in self._op(other))
def __mul__ (self, other): return vec(a*b for a,b in self._op(other))
def __floordiv__(self, other): return vec(a//b for a,b in self._op(other))
def __mod__ (self, other): return vec(a%b for a,b in self._op(other))
def __pow__ (self, other): return vec(a**b for a,b in self._op(other))
def __lshift__ (self, other): return vec(a<<b for a,b in self._op(other))
def __rshift__ (self, other): return vec(a>>b for a,b in self._op(other))
def __and__ (self, other): return vec(a&b for a,b in self._op(other))
def __xor__ (self, other): return vec(a^b for a,b in self._op(other))
def __or__ (self, other): return vec(a|b for a,b in self._op(other))
def __div__ (self, other): return vec(a/b for a,b in self._op(other))
def __truediv__ (self, other): return vec(a/b for a,b in self._op(other))
def __radd__ (self, other): return vec(a+b for b,a in self._op(other))
def __rsub__ (self, other): return vec(a-b for b,a in self._op(other))
def __rmul__ (self, other): return vec(a*b for b,a in self._op(other))
def __rfloordiv__(self, other): return vec(a//b for b,a in self._op(other))
def __rmod__ (self, other): return vec(a%b for b,a in self._op(other))
def __rpow__ (self, other): return vec(a**b for b,a in self._op(other))
def __rlshift__ (self, other): return vec(a<<b for b,a in self._op(other))
def __rrshift__ (self, other): return vec(a>>b for b,a in self._op(other))
def __rand__ (self, other): return vec(a&b for b,a in self._op(other))
def __rxor__ (self, other): return vec(a^b for b,a in self._op(other))
def __ror__ (self, other): return vec(a|b for b,a in self._op(other))
def __rdiv__ (self, other): return vec(a/b for b,a in self._op(other))
def __rtruediv__ (self, other): return vec(a/b for b,a in self._op(other))
def __neg__ (self): return vec(-a for a in self)
def __pos__ (self): return vec(+a for a in self)
def __abs__ (self): return vec(abs(a) for a in self)
def __invert__ (self): return vec(~a for a in self)
def _op(self, other):
from itertools import izip, repeat
try:
if len(self) != len(other): # TypeError if other not a sequence
raise ValueError, 'incompatible vec lengths'
return izip(self, other)
except TypeError:
return izip(self, repeat(other))
def iterable(x):
"""Tests whether x supports iter(x)."""
try:
iter(x)
return True
except TypeError:
return False
def flatten(seq):
"""
Flattens any nested iterables except strings down to a one-dimensional
generator of elements.
Examples:
>>> [x for x in flatten([1,[2,3]])]
[1, 2, 3]
>>> [x for x in flatten([1, xrange(2,4)])]
[1, 2, 3]
>>> [x for x in flatten([1, ("Oh!", [2,3,4])])]
[1, "Oh!", 2, 3, 4]
>>> [x for x in flatten([1,2,3])]
[1, 2, 3]
"""
for x in seq:
if iterable(x) and not isinstance(x, basestring):
for y in flatten(x): yield y
else:
yield x
def test():
def vec_test():
assert vec(1) == vec((1,)) == vec([1]) == (1,)
assert tuple(vec(1,2)) == (1,2)
assert type(vec(1,2)) == vec
assert type(tuple(vec(1,2))) == tuple
assert vec(1,2,3) == vec((1,2,3)) == vec([1,2,3]) == (1,2,3)
assert vec(1)+2 == 1+vec(2) == vec(1)+vec(2) == (1,)+vec(2) == (3,)
assert vec(1,2,3) ** 2 == (1,4,9)
assert 2 ** vec(1,2,3) == (2,4,8)
assert 1 + 2 * vec(3) == (7,)
assert str(vec(1,2,3)) == '(1, 2, 3)'
assert vec(3, 4) + (1, 2.5) == (4, 6.5)
assert vec(3, 4) - (1, 2.5) == (2, 1.5)
assert vec(3, 4) * (1, 2.5) == (3, 10)
assert vec(3, 4) // (1, 2.5) == (3, 1)
assert vec(3,14) % (2, 5) == (1, 4)
assert vec(3, 4) ** (2, 3) == (9, 64)
assert vec(3, 4) << (2, 3) == (12, 32)
assert vec(11, 67) >> (2, 1) == (2, 33)
assert vec(True, 1) & (2, True) == (0, 1)
assert vec(True, 2) ^ (False, 1) == (True, 3)
assert vec(True, False) | False == (True, False)
assert vec(123, 456) / (12, 45) == (123/12, 456/45)
assert -vec(1,2,3.4) == (-1, -2, -3.4)
assert +vec(1,-2,3) == (+1,+(-2),+3)
assert abs(vec(1,-2,3)) == (abs(1), abs(-2), abs(3))
assert ~vec(True, False, 1, 2) == (~True, ~False, ~1, ~2)
assert vec(0, (1, 2), 2 + vec(1, 2, 3)) == (0, 1, 2, 3, 4, 5)
print('vec tests passed')
def flatten_test():
assert [x for x in flatten([1,[2,3]])] == [1, 2, 3]
assert [x for x in flatten([1,xrange(2,4)])] == [1, 2, 3]
assert [x for x in flatten([1,("Oh!",[2,3,4])])] == [1, "Oh!", 2, 3, 4]
assert [x for x in flatten([1,2,3])] == [1, 2, 3]
print('flatten tests passed')
vec_test()
flatten_test()
if __name__ == '__main__': test()
@pyrtsa
Copy link
Author

pyrtsa commented Apr 5, 2010

Added support for vec concatenation using the vec constructor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment