Python元类基类参数未初始化

2admgd59  于 2023-05-02  发布在  Python
关注(0)|答案(1)|浏览(198)

我正在尝试创建一个元类,它可以从它的基类扩展强制参数。
我有以下基类:

class BaseClass(JSONEncoder):
    def __init__(self, field1, field2, ...):
        self.field1 = field1
        self.field2 = field2
        ...

总共有大约10个参数。
然后,我创建一个dict对象,它包含满足BaseClass的所有参数和值,并使用以下命令创建我的元类:

# getMandatoryFields returns {'field1': 'value1', 'field2': 'value2, ...}
mandatory_fields = self.getMandatoryFields(my_data)
ChildClass = type('ChildClass', (BaseClass,), mandatory_fields)

然而,在我尝试扩展dict之前,我得到了一个错误,即BaseClass中所有必需的位置参数都丢失了:

TypeError: __init__() missing 10 required positional arguments: 'field1', 'field2',...

我认为这与dict解包有关,但我似乎无法找到这些值。我假设这是可能的,因为我可以将一个类传递给type构造函数以进行继承,但我似乎找不到答案。

nuypyhwy

nuypyhwy1#

你的代码所做的是创建一个新的类,它拥有你想要的默认值作为类属性--好吧。但它并不涉及__init__函数本身:它仍然需要10个参数-它不知道从类属性中提取默认值。
你必须意识到,虽然在类的__init__方法中接收参数并设置具有相同名称的示例属性是常见的做法,但这只是在纯代码中完成的:语言本身中的nothing()将类(或示例)属性名与__init__中的参数名联系起来。
)好吧,在核心语言中“什么都没有”-尽管这是一种常见的做法,在游戏的后期,Python抛出了dataclasses模块,它确实做到了这一点:假设您需要一个__init__,它的属性与类中声明的属性镜像并自动生成。
如果你的基类上的__init__方法只是这样做,并且不调用其他代码,不对接收到的参数进行操作,什么都不做,你可以在你的问题中使用数据类-通过调用type生成的动态类将覆盖默认值:

In [18]: @dataclasses.dataclass
    ...: class Base:
    ...:     field1: str = ""
    ...:     field2: int = 0
    ...: 

In [19]: new_class = type("new_class", (Base,), {"field1": "foobar", "field2": 42})

In [20]: instance = new_class()

In [21]: instance
Out[21]: new_class(field1='', field2=0)

注意到你没有在基类中编写__init__:数据类将为您生成一个。如果你在__init__中有一些基本代码要执行,数据类支持__post_init__方法,该方法只接收self作为参数,并在设置示例属性后调用:把你需要的代码放在里面。
(注意,这种方法可能与更高级的数据类使用不兼容,例如使用dataclasses.field在基本体中创建更智能的默认值)
如果由于某种原因你不能使用数据类(基类不在你的控制之下,或者它对接收到的参数执行一些计算),那么你需要在你创建的类中创建一个__init__的修饰版本。
我们的想法是构建一个装饰器,它将检查__init__签名中的参数名,并尝试在调用原始__init__之前从类属性中提取这些参数名(如果它们没有作为**kwargs传入)。不过,我认为数据类只适用于您的情况。

相关问题