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

В 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 упаковываться в арги или кварги. Тем не менее, в 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 внутри функции.

Ответы [ 2 ]

58 голосов
/ 26 марта 2012

Вы можете сделать это в 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 [","] )

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

UPDATE:

Последняя документация по Python 3 здесь .

6 голосов
/ 22 сентября 2013

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

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

Кажется, что комментарии основаны на смешении определения функциипостроено по сравнению с тем, как предоставленные аргументы присваиваются параметрам, указанным в определении.

Это определение этой функции, которая имеет 6 параметров.Он вызывается путем передачи ему именованных и безымянных аргументов в вызове функции.

Для этого примера ... Когда аргумент именуется при вызове функции, он может быть предоставлен не по порядку.arg1 и arg2 являются обязательными параметрами, и если они не переданы в функцию в качестве именованных аргументов, то они должны быть назначены в порядке от предоставленных безымянных аргументов.Значения kw1 и kw2 имеют значения по умолчанию, указанные в определении функции, поэтому они не являются обязательными, но если они не указаны в качестве именованных аргументов, они будут использовать любые доступные значения из оставшихся предоставленных безымянных аргументов.Любые оставшиеся безымянные аргументы предоставляются функции в массиве с именем args. Любые именованные аргументы, которые не имеют соответствующего имени параметра в определении функции, предоставляются вызову функции в словаре с именем kwargs.

...