为什么在这种情况下不使用元类?

时间:2014-02-23 11:00:08

标签: python metaclass

我的问题有两个方面:首先,我不明白为什么__new__()元类的MetaBoundedInt方法没有被类BoundedInt的定义调用,其次想知道如何让它发挥作用。在这一点上,我不知道它是否正常工作,因为它甚至没有被执行 - 所以我的问题在这一点上并不是真的(但如果你发现某些东西,或者在这方面有评论或建议,那么感觉自由地提出来。; - )。

我怀疑问题与BoundedInt是内置int的子类而非object的事实有关,但无法在文档中找到任何内容内联的子类必须以某种方式以不同的方式处理。

更新:抱歉,我没有意识到我在使用Python 3.3.4运行脚本。在Python 2.7.6中确实调用了MataBoundInt.__new__()方法 - 所以现在我想知道为什么会有区别。与此同时,我将重新尝试使其工作(这是一个重新打包 - 嵌套 - 进入一个元类,我在Python 2.7.6和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))

2 个答案:

答案 0 :(得分:3)

  

我没有意识到我在使用Python 3.3.4运行脚本。在Python 2.7.6中确实调用了MataBoundInt.__new__()方法 - 所以现在我想知道为什么会有区别。

不同之处在于,在Python 3中,您通过metaclass语句的class关键字参数指定了元类:

class BoundedInt(int, metaclass=MetaBoundedInt):

这已被更改,以便元类可以在类创建过程的早期阶段参与进来,更改变量和函数定义在类语句中的操作方式,而不仅仅是对类的字典进行后处理。有关详细信息,请参阅PEP 3115

答案 1 :(得分:0)

BoundedInt必须是对象的子类?让我查看一下

它使用您的代码按原样为我调用元类(python2.7)。你对物体所说的话虽然为我敲了响。

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__'

尝试运行isinstance(int,object),它为我返回true。

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.
来自http://docs.python.org/2/library/stdtypes.html

所以我认为你可能会遇到旧版本Python的问题..(2.2虽然很老......但是我觉得这些日子我看起来很不走运。)