繁体   English   中英

有没有办法从 class scope 引用对象的基类 __class__?

[英]Is there a way to reference an object's base __class__ from class scope?

我有一系列的类,继承自几个可能的父类中的一个,它们都共享一个基数 class。每个 class 都有一个基于基数 class parameters的类作用域 Dict[str, object] parameters

from copy import deepcopy


class BaseClass:
    parameters = {
        'example_param1': ParamObject(name='example_param1', editable=True),
    }


class MiddleClass(Baseclass):
    parameters = {
        **deepcopy(Baseclass.parameters),
        'example_param2': ParamObject(name='example_param2', editable=False),
    }


class ChildClass(MiddleClass):
    parameters = {
        **deepcopy(MiddleClass.parameters),
        'example_param3': ParamObject(name='example_param3', editable=True),
    }

这个实现完成了工作,但我发现**deepcopy(Baseclass.parameters),行不令人满意。 随着时间的推移,这些子类将由只对编码有基本了解的人进行编辑,所以我想让代码尽可能简单,并且可以剪切和粘贴。

有什么我可以拨打 class scope 来获得super().__class__的等价物吗? 我希望用户能够将基数 class 从MiddleClass更改为MiddleClass2 ,而无需记住在多个位置更改基数 class。

您可以使用__init_subclass__将父类中的参数直接添加到显式定义的parameters属性中,但代价是插入顺序被颠倒(如果这很重要)。

class ParameterBase:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        for pc in cls.__bases__:
            d = getattr(pc, 'parameters', {})
            cls.parameters.update(d)

class BaseClass(ParameterBase):
    parameters = {
        'example_param1': ParamObject(name='example_param1', editable=True),
    }


class MiddleClass(BaseClass):
    parameters = {
        'example_param2': ParamObject(name='example_param2', editable=False),
    }


class ChildClass(MiddleClass):
    parameters = {
        'example_param3': ParamObject(name='example_param3', editable=True),
    }

你可以用元类来做到这一点。 检查 inheritance 树中的所有类,看它们是否具有parameter s 字段。 如果是,则将它们合并在一起并在 class 实例上设置属性。

class ParamMeta(type):
    def __init__(cls, name, bases, dct):
        class_types = [cls] + list(bases)
        parameters = {}
        for class_type in class_types:
            if hasattr(class_type, "parameters"):
                parameters.update(class_type.parameters)
        cls.parameters = parameters
        super().__init__(name, bases, dct)

例子:

class Foo(metaclass=ParamMeta):
    parameters = {"a": "b"}


class Bar(Foo):
    pass


class Fizz(Bar):
    parameters = {"c": "d"}


print(Foo.parameters)
print(Bar.parameters)
print(Fizz.parameters)

输出:

{'a': 'b'}
{'a': 'b'}
{'c': 'd', 'a': 'b'}

如果您的 class 仅继承自一个 class,则可以使用元类:

class Meta(type):
    def __new__(cls, name, parents, namespace):
        namespace['parameters'] = {
            **deepcopy(parents[0].parameters),
            **namespace['parameters']
        }

        return super().__new__(cls, name, parents, namespace)

class MiddleClass(Baseclass, metaclass=Meta):
    parameters = {
        'example_param2': ParamObject(name='example_param2', editable=False),
    }

例如,这当然是一个不处理多个父类的简化版本。

您可以使用元类,例如建议的其他答案,但我不确定新程序员理解起来有多容易。

您可以通过在 class 上调用__bases__来访问 class 继承的类。遗憾的是,在 python 上,您无法引用在 class 主体上创建的 class,这意味着您不能执行以下操作:

class A:
   bases = A.__bases__  # Invalid code, A is not defined yet

如果你想这样做,同时保持参数 static,你可以在 class 定义之后这样做,它会有你正在寻找的确切行为,虽然有点难看:

class BaseClass:
    parameters = {
        'example_param1': ParamObject(name='example_param1', editable=True),
    }


class MiddleClass(Baseclass):
    pass

MidleClass.parameters = {
    **deepcopy(MidleClass.__bases__[0].parameters),
    'example_param2': ParamObject(name='example_param2', editable=False),
}

现在,稍微改进一下,如果你的parameters真的总是一个'Dict[str, object]',你不需要做一个深层复制,因为使用**以功能方式起作用。 您还可以使用__bases__值处理多个父类,以确保捕获每个值。 所以,如果我要这样做,我会做这样的事情:

def base_parameters(cls):
    parameters = {}
    for base in cls.__bases__:
        parameters.update(base.parameters)

    return parameters


class BaseClass:
    parameters = {
        'example_param1': ParamObject(name='example_param1', editable=True),
    }


class MiddleClass(BaseClass):
    pass

MiddleClass.parameters = {
    **base_parameters(MiddleClass),
    'example_param2': ParamObject(name='example_param2', editable=False),
}


class ChildClass(MiddleClass):
    pass

ChildClass.parameters = {
    **base_parameters(ChildClass),
    'example_param3': ParamObject(name='example_param3', editable=True),
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM