如何向派生类的构造函数添加所需的关键字参数?

wil*_*des 1 python arguments keyword-argument pep-3102

我的情况与这个问题几乎相同,除了我需要关键字参数。

我想向派生类添加必需的关键字参数,但不知道如何去做。尝试显而易见的

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
Run Code Online (Sandbox Code Playgroud)

失败是因为我无法列出像ClassBs那样的参数__init__。和

class ClassB(ClassA):

    def __init__(self, *args, **kwargs):
        super(ClassA, self).__init__(*args, **kwargs)
        self.a=a
        self.b=b
        self.c=c
Run Code Online (Sandbox Code Playgroud)

当然不起作用,因为未指定新关键字。

如何向派生类添加必需的关键字参数?__init__

类似的问题:如何将关键字参数添加到 Python 中的派生类的构造函数?

Sha*_*ger 5

不提供默认值,并且关键字参数是必需的:

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
Run Code Online (Sandbox Code Playgroud)

They're still required to be keyword-only, because they come after the *args argument.

This feature was added at the same time as keyword-only arguments in PEP 3102, which states:

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.

To be clear, keyword-only arguments (required or defaulted) are a Python 3 only feature. If you're trying to do this on Python 2, it's impossible to have Python do the work for you, you just have to perform the checks yourself. Move to Python 3; Python 2 hits end of life (no patches, not even for security) at the end of 2019, so new code should target Python 3 anyway.

Just for the record, the code you'd use on Python 2 would be something awful like:

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)
Run Code Online (Sandbox Code Playgroud)

Downside is that it doesn't show up in the initializer/class signature, and it's more expensive (in code written and runtime) to manually pop out arguments like this.