Last active
October 13, 2021 22:29
-
-
Save DRMacIver/267ede36038b0a7d63ebacc9358127de to your computer and use it in GitHub Desktop.
This file contains hidden or 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
""" | |
A module for when you find modern numeric notation far too convenient to use | |
and want to go back to good old fashioned roman numerals. | |
You can import any numeral you like from here and it will work just fine. | |
e.g. | |
>>> from numerals import IX, XVIIIII | |
>>> IX + XVIIIII | |
XXIX | |
Because of the way Python normalizes identifiers you can import any | |
of these with their unicode equivalent, but also because I am lazy | |
(and because my console is stupid about some unicode characters which | |
makes debugging annoying) the repr is ascii only. | |
""" | |
def __getattr__(name): | |
# Copied from here because I am lazy: | |
# https://www.w3resource.com/python-exercises/class-exercises/python-class-exercise-2.php | |
try: | |
rom_val = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} | |
int_val = 0 | |
for i in range(len(name)): | |
if i > 0 and rom_val[name[i]] > rom_val[name[i - 1]]: | |
int_val += rom_val[name[i]] - 2 * rom_val[name[i - 1]] | |
else: | |
int_val += rom_val[name[i]] | |
return Numeral(int_val) | |
except KeyError: | |
return AttributeError(name) | |
class Numeral(int): | |
def __repr__(self): | |
# Copied from here because I am lazy | |
# https://www.w3resource.com/python-exercises/class-exercises/python-class-exercise-1.php | |
val = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] | |
syb = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"] | |
roman_num = "" | |
i = 0 | |
num = self | |
while num > 0: | |
for _ in range(num // val[i]): | |
roman_num += syb[i] | |
num -= val[i] | |
i += 1 | |
return roman_num | |
ARITHMETIC_METHODS = [ | |
"__abs__", | |
"__add__", | |
"__and__", | |
"__bool__", | |
"__ceil__", | |
"__divmod__", | |
"__floor__", | |
"__floordiv__", | |
"__index__", | |
"__int__", | |
"__invert__", | |
"__lshift__", | |
"__mod__", | |
"__mul__", | |
"__neg__", | |
"__or__", | |
"__pos__", | |
"__pow__", | |
"__radd__", | |
"__rand__", | |
"__rdivmod__", | |
"__rfloordiv__", | |
"__rlshift__", | |
"__rmod__", | |
"__rmul__", | |
"__ror__", | |
"__round__", | |
"__rpow__", | |
"__rrshift__", | |
"__rshift__", | |
"__rsub__", | |
"__rtruediv__", | |
"__rxor__", | |
"__sub__", | |
"__truediv__", | |
"__trunc__", | |
"__xor__", | |
] | |
def replace_method(name): | |
orig = getattr(int, name) | |
def accept(*args): | |
result = orig(*args) | |
if isinstance(result, int) and not isinstance(result, Numeral): | |
return Numeral(result) | |
else: | |
return result | |
accept.__name__ = name | |
setattr(Numeral, name, accept) | |
for n in ARITHMETIC_METHODS: | |
replace_method(n) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment