Skip to content

Instantly share code, notes, and snippets.

@DRMacIver
Last active October 13, 2021 22:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DRMacIver/267ede36038b0a7d63ebacc9358127de to your computer and use it in GitHub Desktop.
Save DRMacIver/267ede36038b0a7d63ebacc9358127de to your computer and use it in GitHub Desktop.
"""
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