Quelles sont les utilisations de **kwargs
en Python?
Je sais que vous pouvez faire un objects.filter
sur une table et passer un argument **kwargs
.
Puis-je également le faire pour spécifier des deltas de temps, à savoir timedelta(hours = time1)
?
Comment ça marche exactement? Est-ce que les classes sont "décompactées"? Comme a,b=1,2
?
Vous pouvez utiliser **kwargs
pour permettre à vos fonctions de 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
lors de l'appel de fonctions en créant un dictionnaire d'arguments de mots clés et en le transmettant à 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 son fonctionnement, ainsi que quelques exemples intéressants.
<- Mise à jour ->
Pour les personnes utilisant Python 3, utilisez items () au lieu de iteritems ()
**
décompresse les dictionnaires.
Cette
func(a=1, b=2, c=3)
est le même que
args = {'a': 1, 'b': 2, 'c':3}
func(**args)
C'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)
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 paires clé/valeur. Et ce sont les kwargs. Ok, c'est comme ça.
Le quoi pour 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 saviez pas avant. Maintenant, vous devez l'ajouter à la signature de la fonction myDo.
Ici, vous pouvez lancer kwargs - vous ajoutez simplement 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 peuvent changer.
Ce n'est qu'un bel exemple que vous pourriez trouver utile.
Sur la base du fait qu'un bon échantillon vaut parfois mieux qu'un long discours, j'écrirai deux fonctions en utilisant toutes les facilités de transmission d'arguments variables python (arguments de position et nommés). Vous devriez pouvoir facilement voir ce que cela fait 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
sert de paramètre fictif pour les arguments devant être passés à un appel de fonction
utiliser *args
et **kwargs
pour appeler une fonction
def args_kwargs_test(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
Nous allons maintenant 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)
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)
arg1: 5
arg2: deux
arg3: 3
Bottomline: *args
n’a pas d’intelligence, il interpole simplement les arguments passés aux paramètres (dans l’ordre de gauche à droite) tandis que **kwargs
se comporte de manière intelligente en plaçant la valeur appropriée à la place souhaitée.
kwargs
dans **kwargs
n'est qu'un nom de variable. Vous pouvez très bien avoir **anyVariableName
kwargs
signifie "arguments de mots clés". Mais j'estime qu'ils devraient être appelés "arguments nommés", car il s'agit simplement d'arguments transmis avec des noms (je ne trouve aucune signification pour le mot "mot clé" dans le terme "arguments mot clé". J'imagine que "mot clé" signifie généralement mots réservés par le langage de programmation et ne pouvant donc pas être utilisés par le programmeur pour les noms de variables, rien de tel ne se produit ici dans le cas de kwargs.). Nous attribuons donc les noms param1
et param2
à deux valeurs de paramètre transmises à la fonction comme suit: func(param1="val1",param2="val2")
, au lieu de ne transmettre que les valeurs: func(val1,val2)
. Ainsi, j'estime qu'ils devraient être appelés de manière appropriée "nombre arbitraire d'arguments nommés" car nous pouvons spécifier un nombre quelconque de ces paramètres (c'est-à-dire des arguments) si func
a la signature func(**kwargs)
Cela étant dit, laissez-moi d'abord expliquer les "arguments nommés", puis "nombre arbitraire d'arguments nommés" kwargs
.
arguments nommés
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
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 des variables de tuple et de dict pour des arguments personnalisés
Pour terminer, laissez-moi également noter que nous pouvons passer
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, notez *
et **
dans les appels de fonction ci-dessus. Si nous les omettons, nous pourrions obtenir de mauvais résultats.
Omettre *
dans les arguments de Tuple:
function2("arg1",
tupleCustomArgs, #omitting *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs
)
empreintes
param1: arg1
param2: arg2
param3: arg3
custom Tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1
Au-dessus du tuple, ('custom param1', 'custom param2', 'custom param3')
est imprimé tel quel.
Omettre dict
args:
function2("arg1",
*tupleCustomArgs,
param3="arg3",
param2="arg2",
dictCustomNamedArgs #omitting **
)
donne
dictCustomNamedArgs
^
SyntaxError: non-keyword arg after keyword arg
De plus, vous pouvez également combiner différents modes d’utilisation lorsque vous appelez les fonctions de 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'utilisation:
def print_wrap(arg1, *args, **kwargs):
print(arg1)
print(args)
print(kwargs)
print(arg1, *args, **kwargs)
Tous les arguments spécifiés par pas dans la définition de la fonction seront placés dans la liste args
ou dans la liste kwargs
, selon qu’il s’agit ou non d’arguments mot-clé:
>>> 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 transmis à une fonction, une erreur sera généré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] )
Lorsque 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é à retenir ici est que le nombre variable d'arguments nommés dans l'appel se traduit par un dictionnaire dans la fonction.
C’est un exemple simple à comprendre à propos de décompression python,
>>> 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