About
RSS

Rings ℤ/nℤ by abuse of __init__subclass__


There are many ways to implement the arithmetic of ℤ modulo nℤ in Python. A class with an __init__(self, k, n) for the ring element k mod n is awkward to use because the modulus n is fixed for all members of the ring but must be passed as an argument for each new object. Python's baroque interpretation of object oriented programming has the obscure __init__subclass__ class method. It's called in the parent class when a derived class's object is constructed. This lends itself to the following (very abridged and bowdlerised):

class zmodn:
    @staticmethod
    def mk_init_sub(n):
        def __init__sub(self, k):
            self.k = k % n
            self.n = n
        return __init__sub
        
    def __init_subclass__(cls):
        name = cls.__name__
        u = name.rindex("_"); clsmodstr = name[u+1:]; clsmod = int(clsmodstr)
        cls.__init__ = zmodn.mk_init_sub(clsmod)   # inject constructor

    def __add__(self, other): return self.__class__(self.k + other.k)
    def __neg__(self): return self.__class__(-self.k)
    def __sub__(self, other): return self + (-other)
    # ....
It does the following: if a class inherits from zmodn __init__subclass__ gets called with the new class (as an object). It parses the __name__ of the class from the right to find an underscore, and casts everything right of it into an int as clsmod. The newly created class gets an autogenerated __init__ method, which contains clsmod as closure. Example code
class ring_12(zmodn): pass
two = ring_12(2)
six = ring_12(6)
zero = two*six
The whole zmodn.py has some more methods and injects a __truediv__ operator in classes where the modulus is prime.

Thu, 23 Jan 2025
[/projects] permanent link