如何将必需的关键字参数添加到派生的 class 的构造函数?

How to add required keyword arguments to a derived class's constructor?

我的情况几乎与 this question 相同,只是我需要关键字参数。

我想将 required 关键字参数添加到派生的 class,但不知道如何去做。尝试显而易见的

class ClassA(some.package.Class):

    def __init__(self, *args, **kwargs):
        super(ClassA, self).__init__(*args, **kwargs)

class ClassB(ClassA):

    def __init__(self, *args, a, b, c, **kwargs):
        super(ClassB, self).__init__(*args, **kwargs)
        self.a=a
        self.b=b
        self.c=c

失败,因为我无法为 ClassB__init__ 列出类似的参数。并且

class ClassB(ClassA):

    def __init__(self, *args, **kwargs):
        super(ClassA, self).__init__(*args, **kwargs)
        self.a=a
        self.b=b
        self.c=c

当然不行,因为没有指定新的关键字。

如何为派生的 class 添加 必需的 关键字参数到 __init__

类似问题:How do I add keyword arguments to a derived class's constructor in Python?

不提供默认值,需要关键字参数:

class ClassB(ClassA):
    def __init__(self, *args, a, b, c, **kwargs):
        super().__init__(*args, **kwargs)  # No need to pass arguments to super in Py3
        self.a = a
        self.b = b
        self.c = c

它们仍然需要仅包含关键字,因为它们出现在 *args 参数之后。

此功能是在 PEP 3102 中与仅关键字参数同时添加的,其中指出:

Keyword-only arguments are not required to have a default value. Since Python requires that all arguments be bound to a value, and since the only way to bind a value to a keyword-only argument is via keyword, such arguments are therefore 'required keyword' arguments. Such arguments must be supplied by the caller, and they must be supplied via keyword.

需要明确的是,仅限关键字的参数(必需或默认)是 Python 3 独有的功能。如果您尝试在 Python 2 上执行此操作,Python 不可能为您完成这项工作,您只需要自己执行检查。移动到Python 3; Python 2 在 2019 年底达到生命周期结束(没有补丁,甚至没有安全性),因此新代码应该以 Python 3 为目标。

郑重声明,您在 Python 2 上使用的代码会很糟糕,例如:

class ClassB(ClassA):
    def __init__(self, *args, **kwargs):
        try:
            self.a = kwargs.pop('a')
            self.b = kwargs.pop('b')
            self.c = kwargs.pop('c')
        except KeyError as e:
            # Convert to TypeError to match Python 3 behavior
            raise TypeError("__init__ missing required keyword-only argument: {!s}".format(e))
        super(ClassB, self).__init__(*args, **kwargs)

缺点是它不会出现在 initializer/class 签名中,并且手动弹出这样的参数(在代码编写和运行时)的成本更高。