Frage

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 classBoundedIntand 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 thatBoundedIntis a subclass of the built-inintrather 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))
War es hilfreich?

Lösung

I didn't realize I was running the script with Python 3.3.4. In Python 2.7.6 the MataBoundInt.__new__()method is indeed being called -- so now I'm wondering why there's a difference.

The difference is because in Python 3, you specify a metaclass through the metaclass keyword argument to the class statement:

class BoundedInt(int, metaclass=MetaBoundedInt):

This was changed so that the metaclass could get involved earlier in the class creation process, changing how variable and function definitions operate within the class statement instead of merely postprocessing the class's dict. See PEP 3115 for details.

Andere Tipps

BoundedInt must be a subclass of object? Just let me check up on that

It calls the metaclass new for me (python2.7) using your code as is. What you said about objects rings a bell for me though.

snowy:~$ python -V
Python 2.7.3
snowy:~$ python x.py 
in MetaBoundedInt.__new__()          <==== see
type(v)=BoundedInt, value=100
Traceback (most recent call last):    <==== and this is a separate problem.
  File "x.py", line 53, in <module>
    v += 10
  File "x.py", line 24, in __get__
    @functools.wraps(self.func)
  File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper
    setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'wrapper_descriptor' object has no attribute '__module__'

try running isinstance(int, object) it returns true for me.

Note
Historically (until release 2.2), Python’s built-in types have differed from
user-defined types because it was not possible to use the built-in types as
the basis for object-oriented inheritance. This limitation no longer exists.

from http://docs.python.org/2/library/stdtypes.html So I think you may have problems with old versions of Python.. (2.2 is very old though.. you'd be unlucky to see it these days I reckon).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top