使用python元类和继承的问题

问题描述 投票:0回答:1

我一直在为项目设计元类布局,其中所有类都使用一个自定义元类来加载其定义的配置以及父级。基本上,每个类都定义一个嵌套的Config类,该类将加载到dict,然后子级也可以定义一个,并且该类使用所有父配置,并且覆盖所有新值。

当我将Config类加载到dict之后不删除Config类时,它很好用,但是现在我试图重构和清除名称空间,这会导致问题。新的(断开的)代码如下:

class AbstractConfigMeta(ABCMeta):
    """Parse nested Config classes and fill a new classes config dict."""

    def __new__(mcs, name, bases, namespace):
        """Traverse the MRO backwards from object to load all Config classes.

        Any config declared in sub classes overwrites base classes.
        """
        # get any config defined in parent classes first
        config = {}
        for parent in reversed(bases):
            if hasattr(parent, "config"):
                config.update(parent.config)
        # pop Config class and add values if defined
        config_class = namespace.pop("Config", None)
        if config_class:
            # get all non-magic (i.e. user-defined) attributes
            attributes = {
                key: value
                for key, value in config_class.__dict__.items()
                if not key.startswith("__")
            }
            config.update(attributes)

        namespace["config"] = config
        return super().__new__(mcs, name, bases, namespace)

使用时解析Config类,但现在不使用父级的任何配置。实例化后仍保留嵌套类的旧代码是:

class AbstractConfigMeta(ABCMeta):
    """Parse nested Config classes and fill a new classes config dict."""

    def __new__(mcs, name, bases, namespace):
        """Traverse the MRO backwards from object to load all Config classes.

        Any config declared in sub classes overwrites base classes.
        """
        new_class = super().__new__(mcs, name, bases, namespace)
        new_class.config = {}  # type: ignore

        for parent in reversed(new_class.__mro__):
            config_class = getattr(parent, "Config", None)
            if config_class:
                # get all non-magic attributes from each Config class
                values = {
                    key: value
                    for key, value in config_class.__dict__.items()
                    if not key.startswith("__")
                }
                new_class.config.update(values)  # type: ignore
        return new_class

似乎现在尝试使用元类创建的字典来访问配置,父配置已被丢弃。任何帮助将不胜感激。

更新

该问题原来是由一些使用嵌套Config类但不使用元类的Mixins引起的。在旧代码块中,这很好,但是当从config dict而不是嵌套类更改为获取父config时,任何不使用元类的都将没有此定义,因此将使用不使用其值的Config类。 >

最终工作代码,包括修复和jsbueno建议的边缘案例:

class AbstractConfigMeta(ABCMeta):
    """Parse nested Config classes and fill a new classes config dict."""

    def __new__(mcs, name, bases, namespace):
        """Traverse the MRO backwards from object to load any config dicts.

        Any Config class declared in sub classes overwrites parent classes.
        """
        # pop Config class and add its attributes if defined
        config_class = namespace.pop("Config", None)
        if config_class:
            # get all non-magic (i.e. user-defined) attributes
            attributes = {
                key: value
                for key, value in config_class.__dict__.items()
                if not key.startswith("__")
            }
            if namespace.get("config"):
                warnings.warn(
                    f"A config dict and a config class are defined for {name}."
                    + " Any values in the config dict will be overwritten."
                )
            namespace["config"] = attributes

        new_class = super().__new__(mcs, name, bases, namespace)
        # get any config dicts defined in the MRO (including the current class)
        config = {}
        for parent in reversed(new_class.__mro__):
            if hasattr(parent, "config"):
                config.update(parent.config)  # type: ignore

        new_class.config = config  # type: ignore
        return new_class

我一直在为项目设计元类布局,其中所有类都使用一个自定义元类来加载其定义的配置以及父级。基本上每个类都定义一个嵌套的Config ...

python oop metaclass
1个回答
0
投票

问题是,在新代码中,您正在类显式bases上进行交互,而旧的(有效)代码在__mro__上进行了迭代。

[bases将只产生显式声明的祖先,并且不会访问任何更复杂的层次结构中的“祖父母”或类。

© www.soinside.com 2019 - 2024. All rights reserved.