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?

python 

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.


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

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


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.


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/


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