如何根据类的基恢复类的mro?

2024-04-23 23:41:23 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我们正在实现一个元类,该元类在实例化之前需要知道方法解析顺序。你知道吗

class Meta(type):
    def __new__(cls, name, bases, namespace):
        mro = ...

是否有一种内建的方法来计算mro,即除了重新实现C3 algorithm之外的方法?你知道吗


Tags: 实例方法namenew顺序deftypenamespace
1条回答
网友
1楼 · 发布于 2024-04-23 23:41:23

更简单的方法是只创建一个临时类,提取它的__mro__,计算您的内容,然后为real创建元类:

class Meta(type):
    def __new__(metacls, name, bases, namespace):
        tmp_cls = super().__new__(metacls, name, bases, namespace)
        mro = tmp_cls.__mro__
        del tmp_cls  # Not actually needed, just to show you are done with it.
        ...
        # do stuff
        ...
        new_class = super().__new__(metacls, name, bases, namespace)
        ...
        return new_class

假设这是不可能的,因为对层次结构上的一些超类的元类有疯狂的副作用-那么同样的想法,但是在做之前将基中的类克隆到“存根”类-但是可能的是,重新实现C3算法比这更容易-当然更有效,因为对于每个类,您将创建N**2个存根超类,其中N是类层次结构的深度(如果您选择此路由,则可以缓存)。你知道吗

不管怎样,代码可能是:

stub_cache = {object: object}

def get_stub_class(cls):
    # yields an mro-equivalent with no metaclass side-effects.
    if cls is object:
        return object
    stub_bases = []
    for base in cls.__bases__:
        stub_bases.append(get_stub_class(base))
    if cls not in stub_cache:
        stub_cache[cls] = type(cls.__name__, tuple(stub_bases), {})
    return stub_cache[cls]

def get_future_mro(name, bases):
    stub_bases = tuple(get_stub_class(base) for base in bases)
    stub_cls = type(name, stub_bases, {})
    reversed_cache = {value:key for key, value in stub_cache.items()}
    return [reversed_cache[mro_base] for mro_base in  stub_cls.__mro__[1:]]

class Meta(type):
    def __new__(metacls, name, bases, namespace):
        mro = get_future_mro(name, bases)
        print(mro)
        return super().__new__(metacls, name, bases, namespace)

(这个东西适用于我在交互模式下尝试过的基本情况-但是可能有复杂的边缘情况没有涵盖,有多个元类等等)

相关问题 更多 >