Comprendre kwargs en Python
à quoi sert **kwargs
en Python?
je sais que vous pouvez faire un objects.filter
sur une table et passer dans un argument **kwargs
.
puis-je également le faire pour spécifier des deltas de temps comme timedelta(hours = time1)
?
comment ça marche exactement? Est-ce que c'est classe comme "déballage"? Comme a,b=1,2
?
10 réponses
vous pouvez utiliser **kwargs
pour laisser vos fonctions prendre un nombre arbitraire d'arguments de mots clés ("kwargs" signifie "arguments de mots clés"):
>>> 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
vous pouvez également utiliser la syntaxe **kwargs
lorsque vous appelez des fonctions en construisant un dictionnaire d'arguments de mots clés et en le passant à votre fonction:
>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith
le tutoriel Python contient une bonne explication de la façon dont il fonctionne, avec quelques nice exemple.
< --Update-->
pour les personnes utilisant Python 3, au lieu de iteritems (), utilisez items ()
dictionnaires de déballage
**
dictionnaires non emballés.
Ce
func(a=1, b=2, c=3)
est le même que
args = {'a': 1, 'b': 2, 'c':3}
func(**args)
il est utile si vous devez construire des paramètres:
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)
paramètres D'emballage d'une fonction
def setstyle(**styles):
for key, value in styles.iteritems(): # styles is a regular dictionary
setattr(someobject, key, value)
Cela vous permet d'utiliser la fonction comme ceci:
setstyle(color="red", bold=False)
kwargs est juste un dictionnaire qui est ajouté aux paramètres.
un dictionnaire peut contenir des couples de clés et de valeurs. Et ce sont les kwargs. Ok, c'est de cette façon.
le whatfor n'est pas si simple.
par exemple (très hypothétique) vous avez une interface qui appelle simplement d'autres routines pour faire le travail:
def myDo(what, where, why):
if what == 'swim':
doSwim(where, why)
elif what == 'walk':
doWalk(where, why)
...
Maintenant vous obtenez une nouvelle méthode "drive":
elif what == 'drive':
doDrive(where, why, vehicle)
mais attendez une minute, il y a un nouveau paramètre "véhicule" -- vous ne le connaissiez pas avant. Maintenant, vous devez l'ajouter à la signature de la myDo-fonction.
ici vous pouvez lancer kwargs dans le jeu -- vous ajoutez juste kwargs à la signature:
def myDo(what, where, why, **kwargs):
if what == 'drive':
doDrive(where, why, **kwargs)
elif what == 'swim':
doSwim(where, why, **kwargs)
de cette façon, vous n'avez pas besoin de changer la signature de votre fonction d'interface chaque fois que certaines de vos routines appelées pourraient changer.
C'est juste un bel exemple, vous pourriez trouver kwargs utile.
sur la base du fait qu'un bon échantillon est parfois meilleur qu'un long discours, j'écrirai deux fonctions en utilisant toutes les facilités de passage d'arguments variables python (à la fois des arguments de position et des arguments nommés). Vous devriez facilement être en mesure de voir ce qu'il fait par vous-même:
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)
et voici la sortie:
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})
Motif: *args
et **kwargs
est un espace réservé pour les arguments qui doivent être transmis à un appel de fonction
utilisant *args
et **kwargs
pour appeler une fonction
def args_kwargs_test(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
maintenant, nous allons utiliser *args
pour appeler la fonction définie ci-dessus
#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)
>>> args_kwargs_test(*args)
résultat:
arg1: deux
arg2: 3
arg3: 5
maintenant, en utilisant **kwargs
pour appeler la même fonction
#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)
résultat:
arg1: 5
arg2: deux
arg3: 3
Bottomline: *args
n'a pas d'intelligence, il interpole simplement les args passés aux paramètres (dans l'ordre de gauche à droite) tandis que **kwargs
se comporte intelligemment en plaçant la valeur appropriée @ l'endroit désiré
-
kwargs
dans**kwargs
est juste le nom de la variable. Vous pouvez très bien avoir**anyVariableName
-
kwargs
signifie" arguments de mots clés". Mais je pense qu'ils devraient plutôt être appelés comme "arguments nommés", car ce sont simplement des arguments transmis avec des noms (Je ne trouve aucune signification au mot" mot-clé "dans le terme"arguments de mots-clés". Je suppose que "mot-clé" signifie habituellement des mots réservés par le langage de programmation et donc ne pas être utilisé par le programmeur pour Noms variables. Rien de Tel ne se produit ici en cas de kwargs.). Alors on donne des nomsparam1
etparam2
à deux valeurs paramétriques transmises à la fonction comme suit:func(param1="val1",param2="val2")
, au lieu de passer seulement les valeurs:func(val1,val2)
. Ainsi, je pense qu'ils devraient être correctement appelés "nombre arbitraire d'arguments nommés" comme nous pouvons spécifier n'importe quel nombre de ces paramètres (c'est-à-dire, arguments) sifunc
a la signaturefunc(**kwargs)
ainsi dit que permettez-moi d'expliquer "arguments nommés" d'abord et puis "nombre arbitraire d'arguments nommés" kwargs
.
les arguments Nommés
- nommé args devraient suivre de position args
- l'ordre de named args n'est pas important
-
exemple
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'
nombre Arbitraire d'arguments nommés kwargs
- séquence des paramètres de fonction:
- paramètres de position
- paramètre formel de la capture nombre arbitraire d'arguments (avec le préfixe *)
- nommé paramètres formels
- paramètre formel capturant le nombre arbitraire de paramètres nommés (préfixé par**)
-
exemple
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
passer tuple et dict variables for custom args
pour finir, laissez-moi aussi noter que nous pouvons passer
- "paramètre formel capturant le nombre arbitraire d'arguments" comme tuple variable et
- " paramètre formel capturant le nombre arbitraire de named paramètres "comme variable dict
ainsi, le même appel ci-dessus peut être fait comme suit:
tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}
function2("arg1",
*tupleCustomArgs, #note *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs #note **
)
enfin la note *
et **
dans les appels de fonction ci-dessus. Si nous omettons, nous pouvons obtenir de mauvais résultats.
Omettant *
dans tuple args:
function2("arg1",
tupleCustomArgs, #omitting *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs
)
imprime
param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1
au-dessus de tuple ('custom param1', 'custom param2', 'custom param3')
est imprimé tel quel.
Omettant dict
args:
function2("arg1",
*tupleCustomArgs,
param3="arg3",
param2="arg2",
dictCustomNamedArgs #omitting **
)
donne
dictCustomNamedArgs
^
SyntaxError: non-keyword arg after keyword arg
en plus, vous pouvez également mélanger différents modes d'utilisation lors de l'appel de fonctions kwargs:
def test(**kwargs):
print kwargs['a']
print kwargs['b']
print kwargs['c']
args = { 'b': 2, 'c': 3}
test( a=1, **args )
donne cette sortie:
1
2
3
notez que * * kwargs doit être le dernier argument
Voici une fonction simple qui sert à expliquer l'usage:
def print_wrap(arg1, *args, **kwargs):
print(arg1)
print(args)
print(kwargs)
print(arg1, *args, **kwargs)
tout argument qui est Non spécifié dans la définition de la fonction sera mis dans la liste args
, ou la liste kwargs
, selon qu'il s'agit d'arguments de mots clés ou non:
>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah
si vous ajoutez un argument de mot-clé qui n'est jamais passé à une fonction, une erreur sera soulevée:
>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
voici un exemple que j'espère utile:
#! /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] )
quand vous exécutez le programme, vous obtenez:
$ 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
la clé emporte ici est que le nombre variable d'arguments nommés dans l'appel traduire dans un dictionnaire dans la fonction.