613 votes

Bonne façon d'utiliser ** kwargs en Python

Quelle est la bonne façon d'utiliser **kwargs en Python quand il s'agit de valeurs par défaut?

kwargs renvoie un dictionnaire, mais quelle est la meilleure façon de définir les valeurs par défaut, ou y en a-t-il une? Devrais-je simplement y accéder en tant que dictionnaire? Utilisez obtenir la fonction?

 class ExampleClass:
    def __init__(self, **kwargs):
        self.val = kwargs['val']
        self.val2 = kwargs.get('val2')
 

Une question simple, mais que je ne trouve pas de bonnes ressources. Les gens le font de différentes façons dans le code que j'ai vu et il est difficile de savoir quoi utiliser.

645voto

balpha Points 18387

Vous pouvez passer une valeur par défaut à get() pour les clés qui ne sont pas dans le dictionnaire:

 self.val2 = kwargs.get('val2',"default value")
 

Toutefois, si vous envisagez d'utiliser un argument particulier avec une valeur par défaut particulière, pourquoi ne pas utiliser les arguments nommés en premier lieu?

 def __init__(self, val2="default value", **kwargs):
 

310voto

Alex Martelli Points 330805

Alors que la plupart des réponses sont en train de dire que, par exemple,

def f(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...etc...

est "le même"

def f(foo=None, bar=None, **kwargs):
    ...etc...

ce n'est pas vrai. Dans ce dernier cas, f peut être appelé comme f(23, 42), alors que dans le premier cas, accepte les arguments nommés uniquement - pas de position des appels. Souvent, vous voulez permettre à l'appelant un maximum de flexibilité et, par conséquent, la deuxième forme, comme la plupart des réponses affirmer, il est préférable: mais ce n'est pas toujours le cas. Lorsque vous acceptez de nombreux paramètres facultatifs de qui, en général, seuls quelques-uns sont passés, il peut être une excellente idée (en évitant les accidents et illisible code à vos sites d'appel!) pour forcer l'utilisation d'arguments nommés -- threading.Thread est un exemple. La première forme est la façon dont vous la mettre en Python 2.

L'idiome est tellement important que, dans Python 3, il a maintenant le soutien de la syntaxe: chaque argument après un seul * dans la def signature est le mot-clé seule, qui est, ne peut pas être passé en position d'argument, mais seulement comme un nom. Donc en Python 3, vous pourriez le code ci-dessus:

def f(*, foo=None, bar=None, **kwargs):
    ...etc...

En effet, en Python 3, vous pouvez même avoir des mots clés uniquement arguments qui ne sont pas en option (sans valeur par défaut).

Cependant, Python 2 a encore de longues années de vie productive, il est donc préférable de ne pas oublier les techniques et les expressions idiomatiques qui permettent d'implémenter en Python 2 élément important de la conception des idées qui sont directement pris en charge dans le langage Python 3!

108voto

abhinav Points 1736

Je suggère quelque chose comme ça

 def testFunc( **kwargs ):
    options = {
            'option1' : 'default_value1',
            'option2' : 'default_value2',
            'option3' : 'default_value3', }

    options.update(kwargs)
    print options

testFunc( option1='new_value1', option3='new_value3' )
# {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'}

testFunc( option2='new_value2' )
# {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}
 

Et puis utilisez les valeurs comme vous le souhaitez

dictionaryA.update(dictionaryB) ajoute le contenu de dictionaryB à dictionaryA écrasant toutes les clés en double.

65voto

Vinay Sajip Points 41286

Tu ferais

 self.attribute = kwargs.pop('name', default_value)
 

ou

 self.attribute = kwargs.get('name', default_value)
 

Si vous utilisez pop , vous pouvez vérifier si des valeurs parasites ont été envoyées et prendre les mesures appropriées (le cas échéant).

55voto

S.Lott Points 207588

À l'aide de **kwargs et les valeurs par défaut, c'est facile. Parfois, cependant, vous ne devriez pas être à l'aide de **kwargs en premier lieu.

Dans ce cas, nous ne sommes pas vraiment en faisant le meilleur usage de **kwargs.

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = kwargs.get('val',"default1")
        self.val2 = kwargs.get('val2',"default2")

Le dessus est un "pourquoi?" de la déclaration. C'est le même que

class ExampleClass( object ):
    def __init__(self, val="default1", val2="default2"):
        self.val = val
        self.val2 = val2

Lorsque vous utilisez **kwargs, tu veux dire qu'un mot-clé n'est pas seulement facultatif, mais conditionnelle. Il y a des règles plus complexes que de simples valeurs par défaut.

Lorsque vous utilisez **kwargs, habituellement, vous pouvez dire quelque chose de plus, comme le suivant, où des valeurs par défaut ne s'appliquent pas.

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = "default1"
        self.val2 = "default2"
        if "val" in kwargs:
            self.val = kwargs["val"]
            self.val2 = 2*self.val
        elif "val2" in kwargs:
            self.val2 = kwargs["val2"]
            self.val = self.val2 / 2
        else:
            raise TypeError( "must provide val= or val2= parameter values" )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X