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

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

编辑:请注意,直到运行时我才知道 OtherObjects 是什么

最佳答案

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

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

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

但这应该做你想做的,甚至更多——你只需要从 BaseComponableMeta 继承所有元类,并通过元类“__superclass”属性调用层次结构中的父类(super class):

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)

关于python - 查找在 Python 中重新定义之前使用的 __metaclass__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8842624/

相关文章:

Python type() 不给出确切的类类型而是给出元类类型

c++ - 使用 Boost.Python 设置包装类的元类

python - 在 Python (NumPy) 中高效计算相似度矩阵

python - 这个简单的 python 元类有什么问题?

带有元类的 Python 工厂模式实现

python - 如何使用 Scikit-cuda FFT 安排多个 1d FFT?

python - 重写 __new__ 的基元类生成带有错误 __module__ 的类

python - 有没有办法根据时间戳列出 AzureBlobStorage 中的 blob?

Python、Flask 和 jinja 模板——如何迭代创建服务器端的字典

Python Scrapy 自定义爬取项xml格式