为什么不能同时将 args 和仅关键字参数与 *args 和 **kwargs 混合

Why can't both args and keyword only arguments be mixed with *args and **kwargs simultaneously

我很清楚 python 中 *args 和 **kwargs 的用法,SO 中有很多问题(例如 Use of *args and **kwargs and What does ** (double star/asterisk) and * (star/asterisk) do for parameters?)。

但我想了解的一件事是:为什么不能同时定义强制位置参数、强制 kwarg 参数并最终仍然允许捕获其他参数和 kwarg,如下面的 cant_do_that 所示?

def one_kwarg_is_mandatory(*, b, **kwargs):
    print(b)
    for key, value in kwargs.items():
        print(key, value)    
        
def one_pos_arg_and_one_kwarg_are_mandatory(a, *, b, **kwargs):
    print(a, b)
    for key, value in kwargs.items():
        print(key, value)
      
# I wanted a mandatory arg (a) and possibly parse other args (*args), 
# then a mandatory kwarg (b) and eventually other kwargs (**kwargs)
def cant_do_that(a, *args, *, b, **kwargs):
    print(a, b)
    print(args)
    for key, value in kwargs.items():
        print(key, value)

# not really interested on this because "b" must be a kwarg and hiding 
# it under **kwargs would not be explicit enough for my customer (sometimes myself ;))
def could_do_this_but(a, b, *args, **kwargs):
    print(a, b)
    print(args)
    print(kwargs)

是的,可以删除 could_do_this_but 函数签名中的 b,在函数顶部执行(例如)kwargs.get("b", None) 并在发现时引发一些适当的错误None...但是在函数签名上直接使用“b”将允许更快、更明确的代码开发使用该函数。

正确的语法是def cant_do_that(a, *args, b, **kwargs):。请注意,* 仅使用一次,both 用于标记位置参数的结尾, 用于设置可变位置参数的名称。


function definition is syntactically unique 中的 * 在 positional-or-keyword 和 keyword-only 参数之间的分隔处:

parameter_list_starargs   ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]

简而言之,语法 "*" [parameter] 意味着 **args 在句法上是相同的东西——文字 * 和可选名称——可能只出现一次。使用裸 * 来启动 keyword-only 参数 而无需 接受可变位置参数,并使用命名 *args 来启动 keyword-only 参数 with 采用可变位置参数。

If the form “*identifier” is present, it is initialized to a tuple receiving any excess positional parameters, defaulting to the empty tuple. [...] Parameters after “*” or “*identifier” are keyword-only parameters and may only be passed used keyword arguments.