查找Python中重新定义之前使用的__metaclass__

发布于 2024-12-26 10:22:01 字数 483 浏览 3 评论 0原文

我想重新定义 __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__ 会经历检查类范围内的定义、然后在基类中、然后在全局中检查定义的过程。通常,您会在重新定义中使用类型,并且通常是全局类型,但是,我的其他对象可能重新定义了 __metaclass__。所以在使用类型时,我会忽略它们的定义,并且它们不会运行,对吗?

编辑:请注意,直到运行时我才知道其他对象是什么

I want to redefine a __metaclass__ but I want to fall back to the metaclass which would have been used if I hadn't redefined.

class ComponentMetaClass(type):

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

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


class Component(OtherObjects):
     __metaclass__ = ComponentMetaClass

From what I understand, the __metaclass__ used by default goes through the process of checking for a definition in the scope of the class, then in the bases and then in global. Normally you would use type in the redefinition and that is usually the global one, however, my OtherObjects, may have redefined the __metaclass__. So in using type, I would ignore their definition and they wouldn't run, right?

edit: note that I don't know what OtherObjects are until runtime

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冰雪之触 2025-01-02 10:22:01

正如 @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)

As @unutbu puts it: "Within one class hierarchy, metaclasses must be subclasses of each other. That is, the metaclass of Component must be a subclass of the metaclass of OtherObjects."

Which means your problem is a bit more complicated than you though first - Not only you have to call the proper metaclass from the base classes, but your current metaclass has to properly inherit from then as well.

(hack some code, confront strange behavior, come back 90 min later)
It was tricky indeed - I had to create a class that receives the desired metaclass as a parameter, and which __call__ method generates dynamically a new metaclass, modifying its bases and adding a __superclass attribute to it.

But this should do what you want and some more - you just have to inherit all your metaclasses from BaseComponableMeta and call the superclasses in the hyerarchy through the metaclass "__superclass" attribute:

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)
感性不性感 2025-01-02 10:22:01

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

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


如果 ComponentMetaClassOtherObjectsMeta 都继承(独立)自 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)  

关于使用元类的替代方法,在注释中提到。使用超级:

class Base(object):
    def method(self): pass

class Base1(Base):
    def method(self):
        print('Base1')
        super(Base1,self).method()

class Base2(Base): 
    def method(self):
        print('Base2')
        super(Base2,self).method()

class Component(Base1,Base2):
    pass

c = Component()
c.method()

Within one class hierarchy, metaclasses must be subclasses of each other. That is, the metaclass of Component must be a subclass of the metaclass of OtherObjects.

If you don't name a __metaclass__ for Component then the metaclass of OtherObjects will be used by default.


If ComponentMetaClass and OtherObjectsMeta both inherit (independently) from type:

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

class OtherObjects(object):
    __metaclass__ = OtherObjectsMeta

class Component(OtherObjects):
     __metaclass__ = ComponentMetaClass

then you get this error:

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

but if you make ComponentMetaClass as subclass of OtherObjectsMeta

class ComponentMetaClass(OtherObjectsMeta): pass

then the error goes away.


Perhaps I misread your question. If want ComponentMetaClass.__new__ to call OtherObjectsMeta.__new__, then use 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)  

Regarding an alternative to using metaclasses, mentioned in the comments. Use super:

class Base(object):
    def method(self): pass

class Base1(Base):
    def method(self):
        print('Base1')
        super(Base1,self).method()

class Base2(Base): 
    def method(self):
        print('Base2')
        super(Base2,self).method()

class Component(Base1,Base2):
    pass

c = Component()
c.method()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文