import functools
def isdunder(x):
return isinstance(x, str) and x.startswith('__') and x.endswith('__')
class DunderSet:
def __contains__(self, x):
return isdunder(x)
def wrap_method(method, xtype, cast):
@functools.wraps(method)
def retval(*args, **kwargs):
result = method(*args, **kwargs)
return cast(result) if type(result) == xtype else result
return retval
def wrap_getter(method, xtype, cast, exceptions):
@functools.wraps(method)
def retval(self, name, *args, **kwargs):
result = method(self, name, *args, **kwargs)
return result if name in exceptions else check_type(result, xtype, cast)
return retval
def check_type(value, xtype, cast):
if type(value) == xtype:
return cast(value)
if callable(value):
return wrap_method(value, xtype, cast)
return value
class ClosedMeta(type):
def __new__(meta, name, bases, dct, **kwargs):
if 'exceptions' in kwargs:
exceptions = set(['__new__', '__init__', *map(str, kwargs.pop('exceptions'))])
else:
exceptions = DunderSet()
target = kwargs.pop('target', bases[0] if bases else object)
cls = super().__new__(meta, name, bases, dct, **kwargs)
for base in cls.__mro__:
for name, item in base.__dict__.items():
if isdunder(name) and (base is cls or name not in dct) and callable(item):
if name in ('__getattribute__', '__getattr__'):
setattr(cls, name, wrap_getter(item, target, cls, exceptions))
elif name not in exceptions:
setattr(cls, name, wrap_method(item, target, cls))
return cls
def __init__(cls, *args, **kwargs):
return super().__init__(*args)
class MyInt(int):
def __contains__(self, x):
return x == self
def my_op(self, other):
return int(self * self // other)
class ClosedInt(MyInt, metaclass=ClosedMeta, target=int,
exceptions=['__index__', '__int__', '__trunc__']):
pass
class MyClass(ClosedInt, metaclass=type):
def __add__(self, other):
return 1
print(type(MyInt(1) + MyInt(2)))
print(0 in MyInt(0), 1 in MyInt(0))
print(type(MyInt(4).my_op(16)))
print(type(ClosedInt(1) + ClosedInt(2)))
print(0 in ClosedInt(0), 1 in ClosedInt(0))
print(type(ClosedInt(4).my_op(16)))
print(type(MyClass(1) + ClosedInt(2)))
aW1wb3J0IGZ1bmN0b29scwogCiAKZGVmIGlzZHVuZGVyKHgpOgogICAgcmV0dXJuIGlzaW5zdGFuY2UoeCwgc3RyKSBhbmQgeC5zdGFydHN3aXRoKCdfXycpIGFuZCB4LmVuZHN3aXRoKCdfXycpCiAKIApjbGFzcyBEdW5kZXJTZXQ6CiAgICBkZWYgX19jb250YWluc19fKHNlbGYsIHgpOgogICAgICAgIHJldHVybiBpc2R1bmRlcih4KQogCiAKZGVmIHdyYXBfbWV0aG9kKG1ldGhvZCwgeHR5cGUsIGNhc3QpOgoKICAgIEBmdW5jdG9vbHMud3JhcHMobWV0aG9kKQogICAgZGVmIHJldHZhbCgqYXJncywgKiprd2FyZ3MpOgogICAgICAgIHJlc3VsdCA9IG1ldGhvZCgqYXJncywgKiprd2FyZ3MpCiAgICAgICAgcmV0dXJuIGNhc3QocmVzdWx0KSBpZiB0eXBlKHJlc3VsdCkgPT0geHR5cGUgZWxzZSByZXN1bHQKCiAgICByZXR1cm4gcmV0dmFsCgoKZGVmIHdyYXBfZ2V0dGVyKG1ldGhvZCwgeHR5cGUsIGNhc3QsIGV4Y2VwdGlvbnMpOgogICAgQGZ1bmN0b29scy53cmFwcyhtZXRob2QpCiAgICBkZWYgcmV0dmFsKHNlbGYsIG5hbWUsICphcmdzLCAqKmt3YXJncyk6CiAgICAgICAgcmVzdWx0ID0gbWV0aG9kKHNlbGYsIG5hbWUsICphcmdzLCAqKmt3YXJncykKICAgICAgICByZXR1cm4gcmVzdWx0IGlmIG5hbWUgaW4gZXhjZXB0aW9ucyBlbHNlIGNoZWNrX3R5cGUocmVzdWx0LCB4dHlwZSwgY2FzdCkKCiAgICByZXR1cm4gcmV0dmFsCgoKZGVmIGNoZWNrX3R5cGUodmFsdWUsIHh0eXBlLCBjYXN0KToKICAgIGlmIHR5cGUodmFsdWUpID09IHh0eXBlOgogICAgICAgIHJldHVybiBjYXN0KHZhbHVlKQogICAgaWYgY2FsbGFibGUodmFsdWUpOgogICAgICAgIHJldHVybiB3cmFwX21ldGhvZCh2YWx1ZSwgeHR5cGUsIGNhc3QpCiAgICByZXR1cm4gdmFsdWUKIAogCmNsYXNzIENsb3NlZE1ldGEodHlwZSk6CiAgICBkZWYgX19uZXdfXyhtZXRhLCBuYW1lLCBiYXNlcywgZGN0LCAqKmt3YXJncyk6CiAgICAgICAgaWYgJ2V4Y2VwdGlvbnMnIGluIGt3YXJnczoKICAgICAgICAgICAgZXhjZXB0aW9ucyA9IHNldChbJ19fbmV3X18nLCAnX19pbml0X18nLCAqbWFwKHN0ciwga3dhcmdzLnBvcCgnZXhjZXB0aW9ucycpKV0pCiAgICAgICAgZWxzZToKICAgICAgICAgICAgZXhjZXB0aW9ucyA9IER1bmRlclNldCgpCiAgICAgICAgdGFyZ2V0ID0ga3dhcmdzLnBvcCgndGFyZ2V0JywgYmFzZXNbMF0gaWYgYmFzZXMgZWxzZSBvYmplY3QpCgogICAgICAgIGNscyA9IHN1cGVyKCkuX19uZXdfXyhtZXRhLCBuYW1lLCBiYXNlcywgZGN0LCAqKmt3YXJncykKCiAgICAgICAgZm9yIGJhc2UgaW4gY2xzLl9fbXJvX186CiAgICAgICAgICAgIGZvciBuYW1lLCBpdGVtIGluIGJhc2UuX19kaWN0X18uaXRlbXMoKToKICAgICAgICAgICAgICAgIGlmIGlzZHVuZGVyKG5hbWUpIGFuZCAoYmFzZSBpcyBjbHMgb3IgbmFtZSBub3QgaW4gZGN0KSBhbmQgY2FsbGFibGUoaXRlbSk6CiAgICAgICAgICAgICAgICAgICAgaWYgbmFtZSBpbiAoJ19fZ2V0YXR0cmlidXRlX18nLCAnX19nZXRhdHRyX18nKToKICAgICAgICAgICAgICAgICAgICAgICAgc2V0YXR0cihjbHMsIG5hbWUsIHdyYXBfZ2V0dGVyKGl0ZW0sIHRhcmdldCwgY2xzLCBleGNlcHRpb25zKSkKICAgICAgICAgICAgICAgICAgICBlbGlmIG5hbWUgbm90IGluIGV4Y2VwdGlvbnM6CiAgICAgICAgICAgICAgICAgICAgICAgIHNldGF0dHIoY2xzLCBuYW1lLCB3cmFwX21ldGhvZChpdGVtLCB0YXJnZXQsIGNscykpCiAgICAgICAgcmV0dXJuIGNscwogCiAgICBkZWYgX19pbml0X18oY2xzLCAqYXJncywgKiprd2FyZ3MpOgogICAgICAgIHJldHVybiBzdXBlcigpLl9faW5pdF9fKCphcmdzKQogCiAKY2xhc3MgTXlJbnQoaW50KToKICAgIGRlZiBfX2NvbnRhaW5zX18oc2VsZiwgeCk6CiAgICAgICAgcmV0dXJuIHggPT0gc2VsZgogICAgZGVmIG15X29wKHNlbGYsIG90aGVyKToKICAgICAgICByZXR1cm4gaW50KHNlbGYgKiBzZWxmIC8vIG90aGVyKQogCiAKY2xhc3MgQ2xvc2VkSW50KE15SW50LCBtZXRhY2xhc3M9Q2xvc2VkTWV0YSwgdGFyZ2V0PWludCwKICAgICAgICAgICAgICAgIGV4Y2VwdGlvbnM9WydfX2luZGV4X18nLCAnX19pbnRfXycsICdfX3RydW5jX18nXSk6CiAgICBwYXNzCgpjbGFzcyBNeUNsYXNzKENsb3NlZEludCwgbWV0YWNsYXNzPXR5cGUpOgogICAgZGVmIF9fYWRkX18oc2VsZiwgb3RoZXIpOgogICAgICAgIHJldHVybiAxCiAKcHJpbnQodHlwZShNeUludCgxKSArIE15SW50KDIpKSkKcHJpbnQoMCBpbiBNeUludCgwKSwgMSBpbiBNeUludCgwKSkKcHJpbnQodHlwZShNeUludCg0KS5teV9vcCgxNikpKQogCnByaW50KHR5cGUoQ2xvc2VkSW50KDEpICsgQ2xvc2VkSW50KDIpKSkKcHJpbnQoMCBpbiBDbG9zZWRJbnQoMCksIDEgaW4gQ2xvc2VkSW50KDApKQpwcmludCh0eXBlKENsb3NlZEludCg0KS5teV9vcCgxNikpKQoKcHJpbnQodHlwZShNeUNsYXNzKDEpICsgQ2xvc2VkSW50KDIpKSk=