Je viens d'un milieu statique langues. Quelqu'un peut m'expliquer (espérons-le, par exemple), le monde réel avantages de l'utilisation **kwargs sur les arguments nommés? Pour moi, ils semblent seulement faire l'appel de fonction plus ambigu. Merci.
Réponses
Trop de publicités?Voulez-vous accepter presque arbitraire des arguments nommés pour une série de raisons, et c'est ce que l' **kw
formulaire vous permet de le faire.
La raison la plus commune est de passer les arguments à droite sur une autre fonction vous êtes d'emballage (décorateurs sont un cas, mais LOIN d'être la seule!) - dans ce cas, **kw
desserre le couplage entre l'enveloppe et wrappee, que l'emballage ne doit pas savoir ou de soins sur l'ensemble de la wrappee arguments. En voici un autre, complètement différente raison:
d = dict(a=1, b=2, c=3, d=4)
si tous les noms avaient à être connu à l'avance, alors il est évident que cette approche ne pouvait pas exister, non? Et btw, le cas échéant, je préfère de beaucoup cette façon de faire un dictionnaire dont les clés sont des chaînes de caractères littérales à:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
tout simplement parce que ce dernier est assez ponctuation-lourds et donc moins lisible.
Lorsque aucun des excellentes raisons d'accepter **kwargs
s'applique, alors ne pas l'accepter: c'est aussi simple que cela. OIE, si il n'y a pas de bonne raison de permettre à l'appelant de passe supplémentaire nommé args arbitraire de noms, ne pas permettre que cela arrive -- juste éviter de mettre un **kw
à la fin de la fonction de la signature de l' def
déclaration.
Comme pour l'aide d' **kw
dans un appel, qui vous permet de mettre ensemble l'ensemble exact des arguments nommés que vous devez passer, chacun avec des valeurs correspondantes, dans un dict, indépendamment d'un seul point d'appel, puis utiliser ce dict à l'appel de point. Comparer:
if x: kw['x'] = x
if y: kw['y'] = y
f(**kw)
pour:
if x:
if y:
f(x=x, y=y)
else:
f(x=x)
else:
if y:
f(y=y)
else:
f()
Même avec seulement deux possibilités (et de la très simples!), le manque d' **kw
est aleady la seconde option absolument intenable et insupportable -- imaginez comment il joue quand il y a une demi-douzaine de possibilités, peut-être dans un peu plus riches de l'interaction... sans **kw
, la vie serait absolue de l'enfer dans de telles circonstances!
Une autre raison, vous pourriez vouloir utiliser **kwargs
(et *args
) est si vous êtes extension d'une méthode dans une sous-classe. Vous souhaitez passer tous les arguments sur la super-classe de la méthode, mais vous voulez vous assurer que votre classe continue de travailler même si les changements de signature dans une version ultérieure:
class MySubclass(Superclass):
def __init__(self, *args, **kwargs):
self.myvalue = kwargs.pop('myvalue', None)
super(MySubclass, self).__init__(*args, **kwargs)
Des exemples du monde réel:
Décorateurs - en général, elles sont génériques, de sorte que vous ne pouvez pas spécifier les arguments initiaux:
def decorator(old):
def new(*args, **kwargs):
# ...
return old(*args, **kwargs)
return new
Lieux où vous souhaitez vous faire de la magie avec un nombre inconnu de mot-clé arguments. L'ORM de Django n'est que, par exemple:
Model.objects.filter(foo__lt = 4, bar__iexact = 'bar')
Il y a deux cas de figures:
Première: Vous êtes d'emballage une autre fonction qui prend un certain nombre d'argument mot-clé, mais vous allez juste pour les transmettre:
def my_wrapper(a, b, **kwargs):
do_something_first(a, b)
the_real_function(**kwargs)
Deuxièmement: Vous êtes prêt à accepter tout argument mot-clé, par exemple, pour définir les attributs d'un objet:
class OpenEndedObject:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
foo = OpenEndedObject(a=1, foo='bar')
assert foo.a == 1
assert foo.foo == 'bar'
**kwargs
sont bonnes si vous ne savez pas à l'avance le nom des paramètres. Par exemple, l' dict
constructeur utilise pour initialiser les clés du nouveau dictionnaire.
dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)
In [3]: dict(one=1, two=2)
Out[3]: {'one': 1, 'two': 2}