在Python中重新定义之前查找__metaclass__

时间:2012-01-12 21:31:39

标签: python metaclass

我想重新定义一个__metaclass__但是我想回到我曾经使用的元类,如果我没有重新定义的话。

class ComponentMetaClass(type):

    def __new__(cls, name, bases, dct):

        return <insert_prev_here>.__new__(cls, name, bases, dct)


class Component(OtherObjects):
     __metaclass__ = ComponentMetaClass

据我所知,默认情况下使用的__metaclass__会经历检查类范围内定义的过程,然后是基础,然后是全局。通常你会在重定义中使用type,而且通常是全局类型,但是,我的OtherObjects可能已经重新定义了__metaclass__。所以在使用类型时,我会忽略它们的定义,它们不会运行,对吧?

编辑:请注意,在运行

之前我不知道其他对象是什么

2 个答案:

答案 0 :(得分:3)

正如@unutbu所说:“在一个类层次结构中,元类必须是彼此的子类。也就是说,Component的元类必须是OtherObjects的元类的子类。”

这意味着你的问题比你首先要复杂一点 - 不仅你必须从基类中调用正确的元类,而且你当前的元类也必须从那时起正确继承。

(破解一些代码,面对奇怪的行为,90分钟后回来) 确实很棘手 - 我必须创建一个接收所需元类作为参数的类,并且__call__方法动态生成一个新的元类,修改它的基础并为其添加__superclass属性。

但是这应该做你想要的更多 - 你只需从BaseComponableMeta继承你的所有元类,并通过元类“__superclass”属性调用层次结构中的超类:

from itertools import chain

class Meta1(type):
    def __new__(metacls, name, bases, dct):
        print name
        return type.__new__(metacls, name, bases, dct)

class BaseComponableMeta(type):
    def __new__(metacls, *args, **kw):
        return metacls.__superclass.__new__(metacls, *args, **kw)

class ComponentMeta(object):
    def __init__(self, metaclass):
        self.metaclass = metaclass
    def __call__(self, name, bases,dct):
        #retrieves the deepest previous metaclass in the object hierarchy
        bases_list = sorted ((cls for cls in chain(*(base.mro() for base in bases)))
        , key=lambda s: len(type.mro(s.__class__)))   
        previous_metaclass = bases_list[-1].__class__
        # Adds the "__superclass" attribute to the metaclass, so that it can call
        # its bases:
        metaclass_dict = dict(self.metaclass.__dict__).copy()
        new_metaclass_name = self.metaclass.__name__ 
        metaclass_dict["_%s__superclass" % new_metaclass_name] = previous_metaclass
        #dynamicaly generates a new metaclass for this class:
        new_metaclass = type(new_metaclass_name, (previous_metaclass, ), metaclass_dict)
        return new_metaclass(name, bases, dct)

# From here on, example usage:

class ComponableMeta(BaseComponableMeta):
    pass

class NewComponableMeta_1(BaseComponableMeta):
    def __new__(metacls, *args):
        print "Overriding the previous metaclass part 1"
        return metacls.__superclass.__new__(metacls, *args)

class NewComponableMeta_2(BaseComponableMeta):
    def __new__(metacls, *args):
        print "Overriding the previous metaclass part 2"
        return metacls.__superclass.__new__(metacls, *args)

class A(object):
    __metaclass__ = Meta1


class B(A):
    __metaclass__ = ComponentMeta(ComponableMeta)

# trying multiple inheritance, and subclassing the metaclass once:
class C(B, A):
    __metaclass__ = ComponentMeta(NewComponableMeta_1)

# Adding a third metaclass to the chain:
class D(C):
    __metaclass__ = ComponentMeta(NewComponableMeta_2)

# class with a "do nothing" metaclass, which calls its bases metaclasses:  
class E(D):
    __metaclass__ = ComponentMeta(ComponableMeta)

答案 1 :(得分:1)

在一个类层次结构中,元类必须是彼此的子类。也就是说,Component的元类必须是OtherObjects的元类的子类。

如果您没有为__metaclass__命名Component,则默认情况下将使用OtherObjects的元类。


如果ComponentMetaClassOtherObjectsMeta都从[{1}}继承(独立):

type

然后你得到这个错误:

class OtherObjectsMeta(type): pass
class ComponentMetaClass(type): pass

class OtherObjects(object):
    __metaclass__ = OtherObjectsMeta

class Component(OtherObjects):
     __metaclass__ = ComponentMetaClass

但是如果您将TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases 作为ComponentMetaClass

的子类
OtherObjectsMeta

然后错误就消失了。


也许我误解了你的问题。如果希望class ComponentMetaClass(OtherObjectsMeta): pass 致电ComponentMetaClass.__new__,请使用OtherObjectsMeta.__new__

super

关于使用元类的替代方法,在评论中提到。使用class OtherObjectsMeta(type): def __new__(meta, name, bases, dct): print('OtherObjectsMeta') return super(OtherObjectsMeta,meta).__new__(meta,name,bases,dct) class ComponentMetaClass(OtherObjectsMeta): def __new__(meta, name, bases, dct): print('ComponentMetaClass') return super(ComponentMetaClass,meta).__new__(meta,name,bases,dct)

super