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)))