passer l'argument ** kwargs à une autre fonction avec ** kwargs

152

Je ne comprends pas l'exemple suivant, disons que j'ai ces fonctions:

# 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

Pourquoi la n ° 1 est-elle la bonne solution et la n ° 2 la mauvaise? **kwargsest fondamentalement un dict, donc si je veux transmettre l'argument à openX, je pense que la bonne façon serait de ne pas **donner le dict. Mais python n'aime évidemment pas le second et me dit que j'ai donné 3 arguments au lieu de 2. Alors, quelle est la raison derrière cela?


la source
5
Je me demande pourquoi vous l'appelez **argsdans le code. C'est peut-être le pire nom possible, car les gens le confondront avec*args
John La Rooy
1
Bon je n'utilise jamais vraiment * args, donc j'utilise ** args ^^, mais bon je peux le modifier.

Réponses:

155

Dans le deuxième exemple, vous fournissez 3 arguments: nom de fichier, mode et un dictionnaire ( kwargs). Mais Python attend: 2 arguments formels plus des arguments de mots-clés.

En préfixant le dictionnaire par «**», vous décompressez le dictionnaire kwargsen arguments de mots-clés.

Un dictionnaire (type dict) est une variable unique contenant des paires clé-valeur.

Les "arguments de mots clés" sont des paramètres de méthode clé-valeur.

Tout dictionnaire peut être décompressé en arguments de mot-clé en le préfixant **lors de l'appel de fonction.

gecco
la source
5
Maintenant je comprends. Je pensais que les mots-clés et dict étaient la même chose.
13
"Tout dictionnaire peut être étendu aux mots-clés en le préfixant avec ** lors de l'appel de fonction." <- thats cool
1
Voir aussi: Documentation Python sur les paramètres de mots-clés et le déballage des listes d'arguments
dinosaure
8
Un exemple de code réel rendrait cette réponse beaucoup plus claire.
OrangeDog
13

La **syntaxe indique à Python de collecter les arguments de mot-clé dans un dictionnaire. Le le save2transmet comme un argument non-mot-clé (un objet de dictionnaire). Le openXne voit aucun argument de mot-clé donc le **argsn'est pas utilisé. Il obtient plutôt un troisième argument non-mot-clé (le dictionnaire). Pour résoudre ce problème, modifiez la définition de la openXfonction.

def openX(filename, mode, kwargs):
    pass
Keith
la source
Merci, mais je veux aussi utiliser openX sans enregistrer, donc je dois m'en tenir aux mots-clés. Je pensais que passer des mots-clés était fondamentalement la même chose que transmettre un dict, mais je ne savais pas jusqu'à présent :)
@xMRW Cela ne peut pas être la même chose puisque vous pouvez également passer un dictionnaire comme paramètre à n'importe quelle fonction. Votre n ° 1 est alors le bon.
Keith
8

En développant la réponse de @gecco, voici un exemple qui vous montrera la différence:

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

Ici vous pouvez voir comment déballer un dictionnaire et pourquoi l'envoi d'un dictionnaire échoue

Reda Drissi
la source
1

Parce qu'un dictionnaire est une valeur unique. Vous devez utiliser l'expansion des mots clés si vous souhaitez le transmettre sous forme de groupe d'arguments de mots clés.

Ignacio Vazquez-Abrams
la source
désolé mais qu'est-ce qu'une "expansion de mots clés"? voulez-vous dire que je devrais utiliser dict_var au lieu de ** args et juste utiliser def func (argument, dict_var = 0) ... func (1, {1: "a", 2: "b"})
1

Pour # 2, les arguments seront uniquement un paramètre formel avec une valeur dict, mais pas un paramètre de type mot-clé.

Si vous souhaitez passer un paramètre de type de mot-clé dans un argument de mot-clé, vous devez spécifier ** avant votre dictionnaire, ce qui signifie ** args

Consultez ceci pour plus de détails sur l'utilisation de ** kw

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

Kit Ho
la source
Il y a donc une grande différence entre ** kwargs et dict?
merci, j'aime toujours en savoir plus sur des sujets que je ne comprends pas.