Jaki jest cel i zastosowanie ** kwargs?


763

Jakie są zastosowania **kwargsw Pythonie?

Wiem, że możesz zrobić objects.filterna stole i przekazać **kwargsargument.  

Czy mogę to również zrobić, aby określić delty czasowe, tj. timedelta(hours = time1)?

Jak to dokładnie działa? Czy klasyfikuje się jako „rozpakowywanie”? Jak a,b=1,2?


27
Jeśli wpadniesz na to pytanie jak ja, zobacz także: * args i ** kwargs?
sumid

3
Zadziwiająco zwięzłe wyjaśnienie tutaj : „* zbiera wszystkie argumenty pozycyjne krotki”, „** zbiera wszystkie argumenty w słowniku słów kluczowych”. Kluczowe słowo jest zbierane .
osa

24
Just FYI: kwargsoznacza KeyWord ARGumentS, czyli argumenty, które ustawiły klucze
Richard de Wit

Odpowiedzi:


868

Możesz użyć, **kwargsaby twoje funkcje mogły pobierać dowolną liczbę argumentów słów kluczowych („kwargs” oznacza „argumenty słów kluczowych”):

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

Możesz także użyć **kwargsskładni podczas wywoływania funkcji, konstruując słownik argumentów słów kluczowych i przekazując go do swojej funkcji:

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

Python Tutorial zawiera dobre wyjaśnienie, jak to działa, a także kilka ciekawych przykładów.

<-- Aktualizacja-->

Dla osób używających Python 3 zamiast iteritems (), użyj items ()


1
@ yashas123 Nie; jeśli zapętlisz coś, co jest puste, nic się nie dzieje, więc niezależnie od tego, jaki kod przyjdzie później, działa normalnie.
JG

330

Rozpakowywanie słowników

** rozpakowuje słowniki.

To

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

jest taki sam jak

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

Jest to przydatne, jeśli musisz konstruować parametry:

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)

Parametry pakowania funkcji

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

Pozwala to na użycie następującej funkcji:

setstyle(color="red", bold=False)

13
czy kwarg to tylko nazwa zmiennej, prawda? więc mogę użyć funkcji def func (** args): i czy to działa?
Sriram

11
@ Sriram: Racja. Gwiazdki są ważne. kwargs to tylko nazwa, którą się nazywa, jeśli nie ma nic lepszego. (Zwykle jest.)
Georg Schölly

54
@ Siram: ze względu na czytelność powinieneś trzymać się kwargs - inni programiści to docenią.
johndodo

12
** do unpack dictionaries.>> umysł oszalały / oczywiście! +1 za wyjaśnienie tego fragmentu.
Marc

13
Uwaga: .iteritems()zmieniono nazwę na .items()Python 3.
fnkr

67

kwargs to tylko słownik dodawany do parametrów.

Słownik może zawierać pary klucz-wartość. I to są kwargsy. Okej, tak to jest.

Po co to nie jest takie proste.

Na przykład (bardzo hipotetyczny) masz interfejs, który po prostu wywołuje inne procedury w celu wykonania zadania:

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

Teraz otrzymujesz nową metodę „drive”:

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

Ale poczekaj chwilę, pojawia się nowy parametr „pojazd” - nie znałeś go wcześniej. Teraz musisz dodać go do podpisu funkcji myDo.

Tutaj możesz rzucić kwargs do gry - po prostu dodajesz kwargs do podpisu:

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

W ten sposób nie musisz zmieniać podpisu funkcji interfejsu za każdym razem, gdy niektóre z wywoływanych procedur mogą ulec zmianie.

To tylko jeden dobry przykład, w którym kwargs może być pomocny.


46

Na podstawie tego, że dobra próbka jest czasem lepsza niż długi dyskurs, napiszę dwie funkcje przy użyciu wszystkich funkcji przekazywania argumentów zmiennej python (argumenty pozycyjne i nazwane). Powinieneś łatwo zobaczyć, co robi sam:

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)

A oto wynik:

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})

28

Motyw: *argsi **kwargssłuży jako symbol zastępczy dla argumentów, które należy przekazać do wywołania funkcji

za pomocą *argsi **kwargsdo wywołania funkcji

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

Teraz użyjemy *argsdo wywołania wyżej zdefiniowanej funkcji

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

wynik:

arg1: dwa
arg2: 3
arg3: 5


Teraz za pomocą **kwargswywołuje tę samą funkcję

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

wynik:

arg1: 5
arg2: dwa
arg3: 3

Konkluzja: *argsnie ma inteligencji, po prostu interpoluje przekazane argumenty do parametrów (w kolejności od lewej do prawej), **kwargszachowując się inteligentnie, umieszczając odpowiednią wartość @ wymaganego miejsca


24
  • kwargsin **kwargsto tylko nazwa zmiennej. Możesz bardzo dobrze mieć**anyVariableName
  • kwargsoznacza „argumenty słów kluczowych”. Ale wydaje mi się, że lepiej je nazwać „argumentami nazwanymi”, ponieważ są to po prostu argumenty przekazywane wraz z nazwami (nie znajduję żadnego znaczenia dla słowa „słowo kluczowe” w terminie „argumenty słów kluczowych”. Myślę, że „słowo kluczowe” zwykle oznacza słowa zastrzeżone przez język programowania i dlatego nie mogą być używane przez programistę w nazwach zmiennych. W przypadku kwargs nic takiego się nie dzieje.). Więc dajemy imiona param1i param2dwie wartości parametrów przekazywanych do funkcji w następujący sposób: func(param1="val1",param2="val2")zamiast przechodząc tylko wartości: func(val1,val2). Dlatego uważam, że należy je odpowiednio nazwać „dowolną liczbą nazwanych argumentów”, ponieważ możemy określić dowolną liczbę tych parametrów (to znaczyfuncfunc(**kwargs)

Mówiąc to, pozwól mi najpierw wyjaśnić „nazwane argumenty”, a następnie „dowolną liczbę nazwanych argumentów” kwargs.

Nazwane argumenty

  • nazwane argumenty powinny podążać za argumentami pozycyjnymi
  • kolejność nazwanych argumentów nie jest ważna
  • Przykład

    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'

Dowolna liczba nazwanych argumentów kwargs

  • Sekwencja parametrów funkcji:
    1. parametry pozycyjne
    2. parametr formalny przechwytujący dowolną liczbę argumentów (poprzedzony *)
    3. nazwane parametry formalne
    4. parametr formalny przechwytujący dowolną liczbę nazwanych parametrów (z prefiksem **)
  • Przykład

    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

Przekazywanie zmiennych krotek i dict dla niestandardowych argumentów

Aby to zakończyć, zaznaczę, że możemy przejść

  • "parametr formalny przechwytujący dowolną liczbę argumentów" jako zmienna krotkowa i
  • „parametr formalny przechwytujący dowolną liczbę nazwanych parametrów” jako zmienną dict

W ten sposób powyższe połączenie można wykonać w następujący sposób:

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

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

Wreszcie pamiętać *i **w wywołań funkcji powyżej. Jeśli je pominiemy, możemy mieć złe wyniki.

Pominięcie *argumentów krotkowych:

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

odciski

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

Powyżej krotki ('custom param1', 'custom param2', 'custom param3')jest drukowane tak, jak jest.

Pominięcie dictargumentów:

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

daje

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg

3
Wyobrażam sobie, że keywordterminologia wynika z faktu, że przekazujesz dyktando, które jest bazą danych par klucz-wartość.
crobar

masz na myśli słowo „klucz” w parach „klucz” -wartość? Również nie jest zwykle nazywana bazą danych, ale słownikiem. Ale nadal nie jest w stanie znaleźć żadnego znaczenia dla użycia słowa „słowo kluczowe”.
Mahesha999

9

Dodatkowo możesz także łączyć różne sposoby użycia podczas wywoływania funkcji kwargs:

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


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

test( a=1, **args )

daje ten wynik:

1
2
3

Zauważ, że ** kwargs musi być ostatnim argumentem


5

kwargs to cukier składniowy do przekazywania argumentów nazw jako słowniki (dla func) lub słowniki jako argumenty nazwane (dla func)


5

Oto prosta funkcja, która służy wyjaśnieniu użycia:

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

Wszelkie argumenty, które nie są określone w definicji funkcji, zostaną umieszczone na argsliście lub kwargsliście, w zależności od tego, czy są argumentami słów kluczowych, czy nie:

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

Jeśli dodasz argument słowa kluczowego, który nigdy nie zostanie przekazany do funkcji, pojawi się błąd:

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

1

Oto przykład, który mam nadzieję jest pomocny:

#! /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] )

Po uruchomieniu programu otrzymujesz:

$ 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

Kluczem tutaj jest to, że zmienna liczba nazwanych argumentów w wywołaniu tłumaczy się na słownik funkcji.


0

To prosty przykład na temat rozpakowywania Pythona ,

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

0

W Javie używasz konstruktorów do przeciążania klas i dopuszczania wielu parametrów wejściowych. W Pythonie możesz użyć kwargs, aby zapewnić podobne zachowanie.

przykład java: https://beginnersbook.com/2013/05/constructor-overloading/

przykład python:

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.

tylko inny sposób myślenia o tym.


0

Argumenty słów kluczowych są często w Pythonie skracane do kwargs . W programowaniu komputerowym ,

Argumenty słów kluczowych odnoszą się do obsługi języka komputerowego dla wywołań funkcji, które wyraźnie określają nazwę każdego parametru w wywołaniu funkcji.

Użycie dwóch gwiazdek przed nazwą parametru, ** kwargs , występuje wtedy, gdy nie wiadomo, ile argumentów słowa kluczowego zostanie przekazanych do funkcji. W takim przypadku nazywa się to Arbitrary / Wildcard Keyword Arguments.

Jednym z przykładów są funkcje odbiornika Django .

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

Zauważ, że funkcja przyjmuje argument nadawcy wraz z argumentami słów kluczowych ze znakiem zastępczym (** kwargs); wszystkie programy obsługi sygnałów muszą wziąć te argumenty. Wszystkie sygnały wysyłają argumenty słów kluczowych i mogą je zmienić w dowolnym momencie. W przypadku request_finished jest to udokumentowane jako brak wysyłania argumentów, co oznacza, że ​​możemy mieć pokusę, aby napisać naszą obsługę sygnałów jako my_callback (nadawca).

To byłoby złe - w rzeczywistości Django zgłosi błąd, jeśli to zrobisz. Jest tak, ponieważ w dowolnym momencie do sygnału mogą zostać dodane argumenty, a odbiornik musi być w stanie obsłużyć te nowe argumenty.

Zauważ, że nie musi to być nazywane kwargs , ale musi mieć ** (nazwa kwargs to konwencja).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.