2015-10-15 17 views
6

Ich habe ein schwieriges Verhalten von keyword only arguments Feature in Python3 bei der Verwendung mit partial. Sonstiges info für Schlüsselwort-Argumente.verstehen '*' "nur Schlüsselwort" argument notation in python3 Funktionen

Hier ist mein Code:

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

Hier ist mein Verständnis von Teil:

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

Was habe ich verstanden, in dem obigen Beispiel ist, partial das zweite Argument zu pow Funktion als einzigem macht Argument von two_pow.

Meine Frage ist, warum hat folgende Arbeiten:

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

Aber ich Fehler in diese:

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

Ich weiß, dass ich awesome_function direkt von

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

Antwort

3

Gemäß der Semantik des function calls in Python, die Regeln für die Argumente übergeben werden sind wie folgt

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

Wie Sie hier sehen, sollten die Positionsargumente immer am Anfang der Funktionsaufrufe erscheinen. Sie können nirgendwo anders erscheinen.Wenn Sie

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

tun verletzt es die obige Regel, wie Sie zwei Positionsargumente sind vorbei (3 und 5) nach einem Schlüsselwort-Argument (prefix). Deshalb erhalten Sie eine SyntaxError, da Python den Funktionsaufruf nicht analysieren kann.


Aber, wenn Sie partial verwenden es funktioniert, weil partial eine neue Funktion Objekt erstellt und speichert alle Parameter an sie übergeben werden. Wenn Sie das von partial zurückgegebene Funktionsobjekt tatsächlich aufrufen, wendet es zuerst alle Positionsargumente und dann die Schlüsselwortargumente an.

1

nennen Der Fehler, den Sie bekommen - SyntaxError: non-keyword arg after keyword arg - ist, weil Sie versucht haben, Positionsargumente zu senden (lik e 3,5) nach einem Schlüsselwort-Argument, das ist keine gültige Syntax und daher ein Syntaxfehler. In dem Funktionsaufruf -

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

Es funktioniert bei der Verwendung von functools.partial weil functools.partial kennen Positionsargumente vor Schlüsselwort-Argumenten zu setzen, damit, wenn Sie die Teilfunktion aufrufen - g() - mit Positionsargument, sendet er diese Positionsargumente vor dem Schlüsselwort Streit . Daher in Ihrem Fall g(3, 5) ==> awesome_function(3, 5, prefix='$').

Ein einfaches Beispiel, dies zu zeigen -

>>> 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' 

Im obigen Fall, wenn wir ptfunc(20) genannt, 20 wurde zuerst als Positions Argument übergeben, und dann a=10 das Schlüsselwort-Argument übergeben wurde, also beschwert, dass es hat mehrere Werte für das Argument a.


Und auch als gegeben in the documentation -

functools.partial entspricht in etwa:

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