Вызов функции Python с * args, ** kwargs и необязательными / аргументами по умолчанию

В python я могу определить функцию следующим образом:

def func(kw1=None,kw2=None,**kwargs): ... 

В этом случае я могу вызвать func как:

 func(kw1=3,kw2=4,who_knows_if_this_will_be_used=7,more_kwargs=Ellipsis) 

Я также могу определить функцию как:

 def func(arg1,arg2,*args): ... 

который можно назвать

 func(3,4,additional,arguments,go,here,Ellipsis) 

Наконец, я могу объединить две формы

 def func(arg1,arg2,*args,**kwargs): ... 

Но то, что не работает, вызывает:

 func(arg1,arg2,*args,kw1=None,kw2=None,**kwargs): #SYNTAX ERROR (in python 2 only, apparently this works in python 3) ... 

Моя первоначальная мысль заключалась в том, что это было, вероятно, потому, что функция

 def func(arg1,arg2,*args,kw1=None): ... 

можно назвать

 func(1,2,3) #kw1 will be assigned 3 

Таким образом, это приведет к некоторой двусмысленности относительно того, должны ли 3 быть упакованы в args или kwargs. Однако с помощью python 3 можно указать только аргументы ключевого слова:

 def func(a,b,*,kw=None): #can be called as func(1,2), func(1,2,kw=3), but NOT func(1,2,3) ... 

При этом кажется, что нет синтаксической двусмысленности:

 def func(a,b,*args,*,kw1=None,**kwargs): ... 

Однако это все еще вызывает синтаксическую ошибку (проверенную с помощью Python3.2). Есть ли причина для этого, что мне не хватает? И есть ли способ получить описанное выше поведение (наличие аргументов с аргументами по умолчанию). Я знаю, что смогу имитировать это поведение, манипулируя словарем kwargs внутри функции.

Вы можете сделать это на Python 3.

 def func(a,b,*args,kw1=None,**kwargs): 

Голый * используется только тогда, когда вы хотите указать только аргументы ключевого слова, не принимая переменное число позиционных аргументов с *args . Вы не используете два * s.

Чтобы процитировать из грамматики, в Python 2, у вас есть

 parameter_list ::= (defparameter ",")* ( "*" identifier [, "**" identifier] | "**" identifier | defparameter [","] ) 

в то время как на Python 3 у вас есть

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

который включает положение для дополнительных параметров после параметра * .

Если вы хотите сделать смесь обоих, помните, что * args и ** kwargs должны быть последними указанными параметрами.

 func(arg1,arg2,*args,kw1=None,kw2=None,**kwargs): #Invalid func(arg1,arg2,kw1=None,kw2=None,*args,**kwargs): #Valid