Was ist der Zweck und die Verwendung von ** kwargs?

763

Wozu dient **kwargsPython?

Ich weiß, dass Sie einen objects.filterauf einem Tisch machen und ein **kwargsArgument übergeben können.  

Kann ich dies auch tun, um Zeitdeltas anzugeben, dh timedelta(hours = time1)?

Wie genau funktioniert es? Ist es Klassen als "Auspacken"? Wie a,b=1,2?

Federer
quelle
27
Wenn Sie als ich auf diese Frage stoßen, siehe auch: * args und ** kwargs?
Summe
3
Eine bemerkenswert kurze Erklärung hier : "* sammelt alle Positionsargumente in einem Tupel", "** sammelt alle Schlüsselwortargumente in einem Wörterbuch". Das Schlüsselwort ist Sammeln .
osa
24
Nur zu Ihrer Information: kwargssteht für KeyWord ARGumentS, dh Argumente, die Schlüssel gesetzt haben
Richard de Wit

Antworten:

868

Sie können verwenden **kwargs, damit Ihre Funktionen eine beliebige Anzahl von Schlüsselwortargumenten annehmen ("kwargs" bedeutet "Schlüsselwortargumente"):

>>> def print_keyword_args(**kwargs):
...     # kwargs is a dict of the keyword args passed to the function
...     for key, value in kwargs.iteritems():
...         print "%s = %s" % (key, value)
... 
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe

Sie können die **kwargsSyntax auch beim Aufrufen von Funktionen verwenden, indem Sie ein Wörterbuch mit Schlüsselwortargumenten erstellen und an Ihre Funktion übergeben:

>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith

Das Python-Tutorial enthält eine gute Erklärung der Funktionsweise sowie einige schöne Beispiele.

<--Update-->

Verwenden Sie für Benutzer von Python 3 anstelle von iteritems () items ()

Pär Wieslander
quelle
1
@ yashas123 Nein; Wenn Sie eine leere Schleife durchlaufen, geschieht nichts. Der nächste Code wird also normal ausgeführt.
JG
330

Wörterbücher auspacken

** packt Wörterbücher aus.

Diese

func(a=1, b=2, c=3)

ist das gleiche wie

args = {'a': 1, 'b': 2, 'c':3}
func(**args)

Es ist nützlich, wenn Sie Parameter erstellen müssen:

args = {'name': person.name}
if hasattr(person, "address"):
    args["address"] = person.address
func(**args)  # either expanded to func(name=person.name) or
              #                    func(name=person.name, address=person.address)

Packparameter einer Funktion

def setstyle(**styles):
    for key, value in styles.iteritems():      # styles is a regular dictionary
        setattr(someobject, key, value)

Auf diese Weise können Sie die folgende Funktion verwenden:

setstyle(color="red", bold=False)
Georg Schölly
quelle
13
Ist kwarg nur ein Variablenname, oder? so kann ich def func (** args) verwenden: und es wud funktioniert?
Sriram
11
@ Sriram: Richtig. Die Sternchen sind wichtig. kwargs ist nur der Name, den man gibt, wenn es keinen besseren gibt. (Normalerweise gibt es.)
Georg Schölly
54
@Sriram: Aus Gründen der Lesbarkeit sollten Sie sich an kwargs halten - andere Programmierer werden es zu schätzen wissen.
Johndodo
12
** do unpack dictionaries.>> umwerfend / natürlich! +1 für die Erklärung dieses Bits.
Marc
13
Hinweis: .iteritems()wurde .items()in Python 3 umbenannt .
fnkr
67

kwargs ist nur ein Wörterbuch, das den Parametern hinzugefügt wird.

Ein Wörterbuch kann Schlüssel-Wert-Paare enthalten. Und das sind die Kwargs. Ok, so geht das.

Das Wofür ist nicht so einfach.

Zum Beispiel (sehr hypothetisch) haben Sie eine Schnittstelle, die nur andere Routinen aufruft, um die Arbeit zu erledigen:

def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

Jetzt erhalten Sie eine neue Methode "Laufwerk":

elif what == 'drive':
   doDrive(where, why, vehicle)

Aber Moment mal, es gibt einen neuen Parameter "Fahrzeug" - Sie haben es vorher nicht gewusst. Jetzt müssen Sie es der Signatur der myDo-Funktion hinzufügen.

Hier können Sie Kwargs ins Spiel bringen - Sie fügen der Signatur einfach Kwargs hinzu:

def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

Auf diese Weise müssen Sie die Signatur Ihrer Schnittstellenfunktion nicht jedes Mal ändern, wenn sich einige Ihrer aufgerufenen Routinen ändern.

Dies ist nur ein schönes Beispiel, das Sie als hilfreich erachten könnten.

Jürgen
quelle
46

Auf der Grundlage, dass eine gute Stichprobe manchmal besser ist als ein langer Diskurs, schreibe ich zwei Funktionen unter Verwendung aller Übergabemöglichkeiten für Python-Variablenargumente (sowohl Positions- als auch benannte Argumente). Sie sollten leicht selbst sehen können, was es tut:

def f(a = 0, *args, **kwargs):
    print("Received by f(a, *args, **kwargs)")
    print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
    print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
    g(10, 11, 12, *args, d = 13, e = 14, **kwargs)

def g(f, g = 0, *args, **kwargs):
    print("Received by g(f, g = 0, *args, **kwargs)")
    print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))

print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)

Und hier ist die Ausgabe:

Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs) 
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})
kriss
quelle
28

Motiv: *argsund **kwargsdient als Platzhalter für die Argumente, die an einen Funktionsaufruf übergeben werden müssen

Verwenden *argsund **kwargsAufrufen einer Funktion

def args_kwargs_test(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

Jetzt *argsrufen wir die oben definierte Funktion auf

#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)  
>>> args_kwargs_test(*args)

Ergebnis:

arg1: zwei
arg2: 3
arg3: 5


Verwenden Sie nun **kwargs, um dieselbe Funktion aufzurufen

#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)

Ergebnis:

arg1: 5
arg2: zwei
arg3: 3

Fazit: Hat *argskeine Intelligenz, interpoliert einfach die übergebenen Argumente auf die Parameter (in der Reihenfolge von links nach rechts) und **kwargsverhält sich intelligent, indem der entsprechende Wert an der gewünschten Stelle platziert wird

kmario23
quelle
24
  • kwargsin **kwargsist nur Variablenname. Sie können sehr gut haben**anyVariableName
  • kwargssteht für "Schlüsselwortargumente". Ich bin jedoch der Meinung, dass sie besser als "benannte Argumente" bezeichnet werden sollten, da dies einfach Argumente sind, die zusammen mit Namen weitergegeben werden (ich finde keine Bedeutung für das Wort "Schlüsselwort" im Begriff "Schlüsselwortargumente". Ich denke, "Schlüsselwort" bedeutet normalerweise Wörter, die von der Programmiersprache reserviert sind und daher vom Programmierer nicht für Variablennamen verwendet werden dürfen. Bei kwargs passiert hier nichts dergleichen.). Wir geben also Namen param1und param2zwei Parameterwerte an die Funktion wie folgt übergeben: func(param1="val1",param2="val2")anstatt nur Werte zu übergeben : func(val1,val2). Ich bin daher der Meinung, dass sie angemessen als "beliebige Anzahl benannter Argumente" bezeichnet werden sollten, da wir eine beliebige Anzahl dieser Parameter angeben können (d. H.funcfunc(**kwargs)

Lassen Sie mich also zuerst "benannte Argumente" und dann "beliebige Anzahl benannter Argumente" erklären kwargs.

Benannte Argumente

  • benannte Argumente sollten Positionsargumenten folgen
  • Die Reihenfolge der benannten Argumente ist nicht wichtig
  • Beispiel

    def function1(param1,param2="arg2",param3="arg3"):
        print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
    
    function1(1)                      #1 arg2 arg3   #1 positional arg
    function1(param1=1)               #1 arg2 arg3   #1 named arg
    function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
    function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
    function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
    function1(1, param3=3, param2=2)  #1 2 3         #
    
    #function1()                      #invalid: required argument missing
    #function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
    #function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
    #function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'
    

Beliebige Anzahl benannter Argumente kwargs

  • Reihenfolge der Funktionsparameter:
    1. Positionsparameter
    2. formaler Parameter, der eine beliebige Anzahl von Argumenten erfasst (mit * vorangestellt)
    3. benannte formale Parameter
    4. Formalparameter, der eine beliebige Anzahl benannter Parameter erfasst (mit dem Präfix **)
  • Beispiel

    def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
        print("param1: "+ param1)
        print("param2: "+ param2)
        print("param3: "+ param3)
        print("custom tuple params","-"*10)
        for p in tupleParams:
            print(str(p) + ",")
        print("custom named params","-"*10)
        for k,v in dictionaryParams.items():
            print(str(k)+":"+str(v))
    
    function2("arg1",
              "custom param1",
              "custom param2",
              "custom param3",
              param3="arg3",
              param2="arg2", 
              customNamedParam1 = "val1",
              customNamedParam2 = "val2"
              )
    
    # Output
    #
    #param1: arg1
    #param2: arg2
    #param3: arg3
    #custom tuple params ----------
    #custom param1,
    #custom param2,
    #custom param3,
    #custom named params ----------
    #customNamedParam2:val2
    #customNamedParam1:val1
    

Übergeben von Tupel- und Diktiervariablen für benutzerdefinierte Argumente

Lassen Sie mich zum Schluss noch bemerken, dass wir bestehen können

  • "Formalparameter, der eine beliebige Anzahl von Argumenten erfasst" als Tupelvariable und
  • "Formalparameter, der eine beliebige Anzahl benannter Parameter erfasst" als Diktatvariable

Somit kann der gleiche obige Aufruf wie folgt erfolgen:

tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}

function2("arg1",
      *tupleCustomArgs,    #note *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs     #note **
      )

Schließlich beachten *und **in Funktionsaufrufen oben. Wenn wir sie weglassen, können wir schlechte Ergebnisse erzielen.

Auslassen *in Tupelargumenten :

function2("arg1",
      tupleCustomArgs,   #omitting *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs
      )

druckt

param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1

Das obige Tupel ('custom param1', 'custom param2', 'custom param3')wird so gedruckt, wie es ist.

Argumente weglassen dict:

function2("arg1",
      *tupleCustomArgs,   
      param3="arg3",
      param2="arg2", 
      dictCustomNamedArgs   #omitting **
      )

gibt

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
Mahesha999
quelle
3
Ich würde mir vorstellen, dass die keywordTerminologie von der Tatsache herrührt, dass Sie ein Diktat übergeben, das eine Datenbank von Schlüssel-Wert-Paaren ist.
Crobar
Meinst du "Schlüssel" -Wort in "Schlüssel" -Wertpaaren? Auch wird es normalerweise nicht Datenbank genannt, sondern Wörterbuch. Aber immer noch nicht in der Lage, eine Bedeutung für die Verwendung des Wortes "Schlüsselwort" zu finden.
Mahesha999
9

Zusätzlich können Sie beim Aufrufen von kwargs-Funktionen verschiedene Verwendungsarten mischen:

def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


args = { 'b': 2, 'c': 3}

test( a=1, **args )

gibt diese Ausgabe:

1
2
3

Beachten Sie, dass ** kwargs das letzte Argument sein muss

philipp
quelle
5

kwargs sind ein syntaktischer Zucker, um Namensargumente als Wörterbücher (für func) oder Wörterbücher als benannte Argumente (für func) zu übergeben.


quelle
5

Hier ist eine einfache Funktion, die zur Erklärung der Verwendung dient:

def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

Alle Argumente, die nicht in der Funktionsdefinition angegeben sind, werden in die argsListe oder in die kwargsListe aufgenommen, je nachdem, ob es sich um Schlüsselwortargumente handelt oder nicht:

>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

Wenn Sie ein Schlüsselwortargument hinzufügen, das niemals an eine Funktion übergeben wird, wird ein Fehler ausgegeben:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
naught101
quelle
1

Hier ist ein Beispiel, von dem ich hoffe, dass es hilfreich ist:

#! /usr/bin/env python
#
def g( **kwargs) :
  print ( "In g ready to print kwargs" )
  print kwargs
  print ( "in g, calling f")
  f ( **kwargs )
  print ( "In g, after returning from f")

def f( **kwargs ) :
  print ( "in f, printing kwargs")
  print ( kwargs )
  print ( "In f, after printing kwargs")


g( a="red", b=5, c="Nassau")

g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )

Wenn Sie das Programm ausführen, erhalten Sie:

$ python kwargs_demo.py 
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f

Der Schlüssel zum Mitnehmen ist, dass die variable Anzahl der benannten Argumente im Aufruf in ein Wörterbuch in der Funktion übersetzt wird.

user1928764
quelle
0

Dies ist das einfache Beispiel für das Auspacken von Python .

>>> def f(*args, **kwargs):
...    print 'args', args, 'kwargs', kwargs

eg1:

>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary
Mohideen bin Mohammed
quelle
0

In Java verwenden Sie Konstruktoren, um Klassen zu überladen und mehrere Eingabeparameter zuzulassen. In Python können Sie kwargs verwenden, um ein ähnliches Verhalten bereitzustellen.

Java-Beispiel: https://beginnersbook.com/2013/05/constructor-overloading/

Python-Beispiel:

class Robot():
    # name is an arg and color is a kwarg
    def __init__(self,name, color='red'):
        self.name = name
        self.color = color

red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')

print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))

>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.

nur eine andere Art, darüber nachzudenken.

Aidan Melen
quelle
0

Schlüsselwortargumente werden in Python häufig zu kwargs verkürzt . In Computer - Programmierung ,

Schlüsselwortargumente beziehen sich auf die Unterstützung einer Computersprache für Funktionsaufrufe, in denen der Name jedes Parameters innerhalb des Funktionsaufrufs eindeutig angegeben ist.

Die Verwendung der beiden Sternchen vor dem Parameternamen ** kwargs ist, wenn man nicht weiß, wie viele Schlüsselwortargumente an die Funktion übergeben werden. In diesem Fall wird es als Arbitrary / Wildcard Keyword Arguments bezeichnet.

Ein Beispiel hierfür sind die Empfängerfunktionen von Django .

def my_callback(sender, **kwargs):
    print("Request finished!")

Beachten Sie, dass die Funktion ein Absenderargument zusammen mit Platzhalter-Schlüsselwortargumenten (** kwargs) verwendet. Alle Signalhandler müssen diese Argumente verwenden. Alle Signale senden Schlüsselwortargumente und können diese Schlüsselwortargumente jederzeit ändern. Im Fall von request_finished wird dokumentiert, dass keine Argumente gesendet werden. Dies bedeutet, dass wir möglicherweise versucht sind, unsere Signalbehandlung als my_callback (Absender) zu schreiben.

Dies wäre falsch - tatsächlich wird Django einen Fehler auslösen, wenn Sie dies tun. Dies liegt daran, dass zu jedem Zeitpunkt Argumente zum Signal hinzugefügt werden können und Ihr Empfänger in der Lage sein muss, diese neuen Argumente zu verarbeiten.

Beachten Sie, dass es nicht kwargs heißen muss , sondern ** (der Name kwargs ist eine Konvention).

Tiago Martins Peres 李大仁
quelle