Created
April 5, 2010 13:03
-
-
Save pyrtsa/356316 to your computer and use it in GitHub Desktop.
class vec(tuple)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added support for vec concatenation using the vec constructor.