Path: blob/main/python/pylang/test/operator_overloading.py
1396 views
def xgcd(a, b):1prevx, x = 1, 02prevy, y = 0, 13while b:4q, r = divmod(a, b)5x, prevx = prevx - q * x, x6y, prevy = prevy - q * y, y7a, b = b, r8return a, prevx, prevy91011def inverse_mod(a, N):12"""13Compute multiplicative inverse of a modulo N.14"""15if a == 1 or N <= 1: # common special cases16return a % N17[g, s, _] = xgcd(a, N)18if g != 1:19raise ZeroDivisionError20b = s % N21if b < 0:22b += N23return b242526class Mod:27def __init__(self, x, n):28self.n = int(n)29self.x = int(x) % self.n30if self.x < 0:31self.x += self.n3233def __eq__(self, right):34if not isinstance(right, Mod):35try:36right = Mod(right, self.n)37except:38return False39return self.x == right.x and self.n == right.n4041def __pow__(self, right, n): # not implemented yet42"""Dumb algorithm, of course."""43if n == 0:44return Mod(1, self.n)45ans = Mod(self.x, self.n)46for i in range(n - 1):47ans *= self48return ans4950def __add__(self, right):51return Mod(self.x + right.x, self.n)5253def __mul__(self, right):54return Mod(self.x * right.x, self.n)5556def __sub__(self, right):57return Mod(self.x - right.x, self.n)5859def __div__(self, right):60if right.x != 1:61raise NotImplementedError62return Mod(self.x, self.n)6364def __truediv__(self, right):65return Mod(self.x * inverse_mod(right.x, self.n), self.n)6667def __floordiv__(self, right):68"""Silly arbitrary meaning of this for TESTING."""69return Mod(self.x // right.x, self.n)7071def __repr__(self):72print(f"Mod({self.x}, {self.n})")7374def __str__(self):75print(f"Mod({self.x}, {self.n})")7677class Mod_inplace(Mod):78def __iadd__(self, right):79self.x = (self.x + right.x) % self.n80return self8182def __imul__(self, right):83self.x = (self.x * right.x) % self.n84return self8586def __isub__(self, right):87self.x = (self.x - right.x) % self.n88if self.x < 0:89self.x += n90return self9192def __idiv__(self, right):93if right.x != 1:94raise NotImplementedError95return self96979899def test1():100#print('test1')101a = Mod(3, 10)102b = Mod(5, 10)103c = a * b104assert c.x == 5105assert (a * (b / a)).x == b.x106assert (b // a).x == 1107108109test1()110111112def test_arith():113#print("test_arith")114a = Mod(17, 35)115b = Mod(2, 35)116assert a + b == Mod(19, 35)117assert b - a == 20118119120test_arith()121122123def test_inplace_fallback():124a = Mod(3, 12)125b = Mod(2, 12)126a['foo'] == 'bar'127a += b128assert a == Mod(5, 12)129assert !a['foo']130a *= b131assert a == Mod(10, 12)132a -= b133assert a == Mod(8, 12)134c = Mod(1,12)135a /= c136assert a== Mod(8, 12)137test_inplace_fallback()138139140def test_inplace():141a = Mod_inplace(3, 12)142a['foo'] = 'bar'143b = Mod_inplace(2, 12)144a += b145assert a['foo'] == 'bar'146assert a == Mod_inplace(5, 12)147a *= b148assert a == Mod_inplace(10, 12)149a -= b150assert a == Mod_inplace(8, 12)151c = Mod(1,12)152a /= c153assert a== Mod_inplace(8, 12)154test_inplace()155156def test_equality():157#print("test_equality")158a = Mod(3, 10)159b = Mod(5, 10)160assert not (a == b)161assert a == a162assert b == b163assert a != b164assert a == 13165assert a != 'fred'166167168test_equality()169170171class IntegerModRing:172def __init__(self, n):173self._n = n174175def __repr__(self):176return f"Ring of Integers Modulo {self._n}"177178def __call__(self, x):179return Mod(x, self._n)180181182# We have chosen NOT to allow overloading183# of __call__, since I can't find any way184# to do it sufficiently efficiently. We185# are NOT implemented the full Python language.186# That's not the goal.187188189def test_integer_mod_ring():190R = IntegerModRing(10)191assert repr(R) == 'Ring of Integers Modulo 10'192a = R.__call__(13)193assert (a == Mod(3, 10))194195196test_integer_mod_ring()197198199class ComplicatedCall:200def __call__(self, x, *args, **kwds):201return [x, args, kwds]202203204def test_complicated_call():205C = ComplicatedCall()206v = C(10)207assert v[0] == 10208# little awkward so test passes in pure python too209assert len(v[1]) == 0210assert v[2] == {}211212v = C(10, 'y', z=2, xx='15')213assert v[0] == 10214assert v[1][0] == 'y'215assert v[2] == {'z': 2, 'xx': '15'}216217218test_complicated_call()219220221def test_attribute_call():222R = IntegerModRing(10)223z = {'R': R}224# We only implement __call__ in a special case225# that does NOT include this. The lhs must be an identifier.226assert z['R'].__call__(3) == Mod(3, 10)227228229test_attribute_call()230231### Absolute value232233234class X:235def __abs__(self):236return 10237238239assert abs(X()) == 10240241242