przekazuje argument ** kwargs do innej funkcji z ** kwargs

152

Nie rozumiem poniższego przykładu, powiedzmy, że mam te funkcje:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

Dlaczego nr 1 jest właściwym rozwiązaniem, a nr 2 niewłaściwym? **kwargsjest w zasadzie dyktando, więc jeśli chcę przekazać argument do openX, myślę, że właściwy sposób byłby bez **i po prostu podając dyktando. Ale Python oczywiście nie lubi drugiego i mówi mi, że podałem 3 zamiast 2 argumentów. Więc jaki jest tego powód?


źródło
5
Zastanawiam się, dlaczego nazywasz to **argsw kodzie. To prawdopodobnie najgorsza możliwa nazwa, z którą ludzie będą je mylić*args
John La Rooy
1
Cóż, tak naprawdę nigdy nie używam * args, więc używam ** args ^^, ale mogę to zmodyfikować.

Odpowiedzi:

155

W drugim przykładzie podajesz 3 argumenty: nazwa pliku, tryb i słownik ( kwargs). Ale Python oczekuje: 2 argumentów formalnych plus argumenty słów kluczowych.

Przedrostkiem słownika „**” można rozpakować słownik kwargsna argumenty słów kluczowych.

Słownik (typ dict) to pojedyncza zmienna zawierająca pary klucz-wartość.

„Argumenty słów kluczowych” to para klucz-wartość parametrów metody.

Każdy słownik można rozpakować jako argumenty słów kluczowych, poprzedzając go **podczas wywołania funkcji.

gecco
źródło
5
teraz rozumiem. Myślałem, że słowa kluczowe i dyktowanie to to samo.
13
„Każdy słownik można rozszerzyć na słowa kluczowe, poprzedzając go przedrostkiem ** podczas wywołania funkcji”. <- to super
1
Zobacz też: Dokumentacja Pythona dotycząca parametrów słów kluczowych i rozpakowywania list argumentów
dinozaur
8
Rzeczywisty przykład kodu uczyniłby tę odpowiedź znacznie bardziej przejrzystą.
OrangeDog
13

**Składnia mówi Python zebrać argumenty słowa kluczowego w słowniku. save2Przechodzi go jako argumentu niż słowa kluczowego (słownikiem obiektu). openXNie widzi żadnych argumentów słów kluczowych, więc **argsnie przyzwyczaić. Zamiast tego pobiera trzeci argument niebędący słowem kluczowym (słownik). Aby to naprawić, zmień definicję openXfunkcji.

def openX(filename, mode, kwargs):
    pass
Keith
źródło
Dziękuję, ale chcę też używać openX bez zapisywania, więc muszę trzymać się słów kluczowych. Myślałem, że przekazywanie słów kluczowych jest w zasadzie tym samym, co przekazywanie dyktu, ale nie wiedziałem do tej pory :)
@xMRW Nie mogą być tym samym, ponieważ możesz przekazać słownik jako parametr również do dowolnej funkcji. Twój numer 1 jest więc właściwy.
Keith
8

Rozwijając odpowiedź @gecco, poniżej znajduje się przykład, który pokaże różnicę:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Tutaj możesz zobaczyć, jak działa rozpakowywanie słownika i dlaczego wysłanie rzeczywistego słownika kończy się niepowodzeniem

Reda Drissi
źródło
1

Ponieważ słownik to pojedyncza wartość. Musisz użyć rozszerzenia słów kluczowych, jeśli chcesz przekazać je jako grupę argumentów słów kluczowych.

Ignacio Vazquez-Abrams
źródło
przepraszam, ale co to jest „rozszerzenie słów kluczowych”? czy masz na myśli, że powinienem użyć dict_var zamiast ** args i po prostu użyć def func (argument, dict_var = 0) ... func (1, {1: "a", 2: "b"})
1

Dla # 2 argumenty będą tylko formalnym parametrem z wartością dict, ale nie będą parametrem typu słowa kluczowego.

Jeśli chcesz przekazać parametr typu słowa kluczowego do argumentu słowa kluczowego, musisz określić ** przed swoim słownikiem, co oznacza ** argumenty

sprawdź to, aby uzyskać więcej informacji na temat używania ** kw

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/

Kit Ho
źródło
Więc jest duża różnica między ** kwargs i dict?
dziękuję, zawsze lubię czytać więcej na tematy, których nie rozumiem.