2015-10-15 11 views
6

Mam pewne zachowanie związane z trudnościami w funkcji keyword only arguments w python3 używane z partial. Inne info tylko dla argumentów zawierających słowa kluczowe.zrozumienie notacji argumentu "*" "tylko słowo kluczowe" w funkcjach python3

Oto mój kod:

def awesome_function(a = 0, b = 0, *, prefix): 
    print('a ->', a) 
    print('b ->', b) 
    print('prefix ->', prefix) 
    return prefix + str(a+b) 

Oto moje rozumienie częściowej:

>>> two_pow = partial(pow, 2) 
>>> two_pow(5) 
32 
>>> 

Co mam rozumieć to w powyższym przykładzie, partial sprawia, że ​​drugi argument do pow funkcji jako jedyny Argument z two_pow.

Moje pytanie brzmi, dlaczego następujące prace:

>>> g = partial(awesome_function, prefix='$') 
>>> g(3, 5) 
a -> 3 
b -> 5 
prefix -> $ 
'$8' 
>>> 

ale pojawia się błąd w tym:

>>> awesome_function(prefix='$', 3, 5) 
    File "<stdin>", line 1 
SyntaxError: non-keyword arg after keyword arg 
>>> 

wiem, że mogę zadzwonić awesome_function bezpośrednio

>>> awesome_function(prefix='$', a = 3, b = 5) 
a -> 3 
b -> 5 
prefix -> $ 
'$8' 
>>> 

Odpowiedz

3

Zgodnie semantyki function calls in Python, zasady argumenty mają być przekazywane są następujące:

argument_list ::= positional_arguments ["," keyword_arguments] 
         ["," "*" expression] ["," keyword_arguments] 
         ["," "**" expression] 
        | keyword_arguments ["," "*" expression] 
         ["," keyword_arguments] ["," "**"  expression] 
        | "*" expression ["," keyword_arguments] ["," "**" expression] 
        | "**" expression 

Jak widać, argumenty pozycyjne powinny zawsze pojawiać się na początku wywołań funkcji. Nie mogą pojawić się nigdzie indziej.Kiedy robisz

awesome_function(prefix='$', 3, 5) 

narusza powyższą regułę, jak mijają dwa argumenty pozycyjne (3 i 5) po argument słowa kluczowego (prefix). Właśnie dlatego uzyskujesz SyntaxError, ponieważ Python nie może przeanalizować wyrażenia wywołania funkcji.


Ale gdy używasz partial to działa, bo partial tworzy nowy obiekt funkcyjny i przechowuje wszystkie parametry mają być przekazane do niego. Kiedy faktycznie wywołasz obiekt funkcji zwrócony przez partial, najpierw stosuje on wszystkie argumenty pozycyjne, a następnie argumenty słów kluczowych.

1

Błąd, który otrzymujesz - SyntaxError: non-keyword arg after keyword arg - jest spowodowany próbą wysłania argumentów pozycyjnych (lik e 3,5) po argumencie słowa kluczowego, który nie jest poprawną składnią, a zatem błędem składni. W wywołaniu funkcji -

awesome_function(prefix='$', 3, 5) 
         ^^^ 
          |  These two are the positional argument. 
          ----- This is the keyword argument.         

Działa przy użyciu functools.partial ponieważ functools.partial wie umieścić pozycyjnych argumentów przed argumentów kluczowych, stąd podczas wywoływania częściowej funkcji - g() - z pozycyjnych argumentów, wysyła te pozycyjnych argumentów przed słowem kluczowym argument . Dlatego w twoim przypadku g(3, 5) ==> awesome_function(3, 5, prefix='$').

Prosty przykład to pokazać -

>>> from functools import partial 
>>> def func(a=0,b=1): 
...  print(a,b) 
... 
>>> ptfunc = partial(func,a=10) 
>>> ptfunc(20) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: func() got multiple values for argument 'a' 

W powyższym przypadku, kiedy zadzwoniliśmy ptfunc(20), 20 został przekazany jako pozycyjnym argumentu, a potem argument kluczowe a=10 została uchwalona, ​​stąd też skarżył się, że to otrzymał wiele wartości dla argumentu a.


A także, jak podano w the documentation -

functools.partial jest grubsza odpowiada:

def partial(func, *args, **keywords): 
    def newfunc(*fargs, **fkeywords): 
     newkeywords = keywords.copy() 
     newkeywords.update(fkeywords) 
     return func(*(args + fargs), **newkeywords) 
    newfunc.func = func 
    newfunc.args = args 
    newfunc.keywords = keywords 
    return newfunc