My question is two-fold: First, I don't understand why the__new__()
method of theMetaBoundedInt
metaclass is not being called by the definition of the classBoundedInt
and secondly would like to know how to get it work. At this point, I don't know if it works properly since it's not even being executed -- so my question is not really about that at this point (but if you spot something, or have a comment or suggestion in that regard, feel free to to bring it up. ;-).
I suspect the problem has something to do with fact thatBoundedInt
is a subclass of the built-inint
rather thanobject
, but was unable to find anything in the documentation indicating that subclassing a built-in had to be handled differently somehow.
Update: Sorry I didn't realize I was running the script with Python 3.3.4. In Python 2.7.6 the MetaBoundInt.__new__()
method is indeed being called -- so now I'm wondering why there's a difference. Meanwhile I'll get back to trying to make it work (this is a repackaging -- nesting -- into a metaclass, of some code I had working in both Python 2.7.6 and Python 3.3.4).
import functools
class MetaBoundedInt(type):
# int arithmetic methods that return an int
_specials = ('abs add and div floordiv invert lshift mod mul neg or pos '
'pow radd rand rdiv rfloordiv rlshift rmod rmul ror rpow '
'rrshift rshift rsub rtruediv rxor sub truediv xor').split()
_ops = set('__%s__' % name for name in _specials)
def __new__(cls, name, bases, attrs):
print('in MetaBoundedInt.__new__()')
classobj = type.__new__(cls, name, bases, attrs)
# create wrappers for all inherited int arithmetic ops
for name, meth in ((n, m) for n, m in vars(int).items() if n in cls._ops):
setattr(classobj, name, cls._DecoratedIntMethod(cls, meth))
return classobj
class _DecoratedIntMethod(object):
def __init__(self, cls, func):
self.cls, self.func = cls, func
def __get__(self, obj, cls=None):
# assume obj is a BoundedInt instance
@functools.wraps(self.func)
def wrapper(*args, **kwargs):
# return result of calling self.func() as BoundedInt
return self.cls(self.func(obj, *args, **kwargs),
bounds=obj._bounds)
return wrapper
class BoundedInt(int):
__metaclass__ = MetaBoundedInt
def __new__(cls, *args, **kwargs):
lower, upper = bounds = kwargs.pop('bounds')
val = int.__new__(cls, *args, **kwargs) # support multiple int() args
if val < lower:
val = int.__new__(cls, lower)
elif val > upper:
val = int.__new__(cls, upper)
val._bounds = bounds
return val
if __name__ == '__main__':
v = BoundedInt('64', 16, bounds=(0, 100)) # 0x64 == 100
print('type(v)={}, value={}'.format(type(v).__name__, v))
v += 10
print('type(v)={}, value={}'.format(type(v).__name__, v))
w = v + 10
print('type(v)={}, value={}'.format(type(w).__name__, w))
x = v - 110
print('type(v)={}, value={}'.format(type(x).__name__, x))