web-dev-qa-db-fra.com

Comment ignorer les arguments de mots clés inattendus passés à une fonction?

Supposons que j'ai une fonction, f:

def f (a=None):
    print a

Maintenant, si j'ai un dictionnaire tel que dct = {"a":"Foo"}, Je peux appeler f(**dct) et obtenir le résultat Foo imprimé.

Cependant, supposons que j'ai un dictionnaire dct2 = {"a":"Foo", "b":"Bar"}. Si j'appelle f(**dct2) j'obtiens un

TypeError: f() got an unexpected keyword argument 'b'

C'est suffisant. Cependant, existe-t-il de toute façon, dans la définition de f ou dans son appel, de dire Python d'ignorer simplement les clés qui ne sont pas des noms de paramètres? De préférence une méthode qui permet de spécifier les valeurs par défaut.

31
rspencer

En tant qu'extension de la réponse publiée par @Bas, je suggérerais d'ajouter les arguments kwargs (arguments de mots clés de longueur variable) comme deuxième paramètre de la fonction

>>> def f (a=None, **kwargs):
    print a


>>> dct2 = {"a":"Foo", "b":"Bar"}
>>> f(**dct2)
Foo

Cela suffirait nécessairement au cas

  1. ignorer simplement les clés qui ne sont pas des noms de paramètres
  2. Cependant, il manque les valeurs par défaut des paramètres, ce qui est une fonctionnalité intéressante qu'il serait agréable de conserver
24
Abhijit

Cela peut être fait en utilisant **kwargs , qui vous permet de collecter tous les arguments de mots clés non définis dans un dict:

def f(**kwargs):
    print kwargs['a']

Test rapide:

In [2]: f(a=13, b=55)
13

[~ # ~] modifier [~ # ~] Si vous souhaitez toujours utiliser les arguments par défaut, vous conservez l'argument d'origine avec la valeur par défaut, mais vous ajouter le **kwargs pour absorber tous les autres arguments:

In [3]: def f(a='default_a', **kwargs):
   ...:     print a
   ...:     

In [4]: f(b=44, a=12)
12
In [5]: f(c=33)
default_a
13
Bas Swinckels

Si vous ne pouvez pas modifier la définition de la fonction pour prendre des kwargs ** non spécifiés, vous pouvez filtrer le dictionnaire que vous transmettez par les arguments de mot-clé en utilisant la fonction argspec dans les anciennes versions de python ou la méthode d'inspection de signature dans Python 3.6.

import inspect
def filter_dict(dict_to_filter, thing_with_kwargs):
    sig = inspect.signature(thing_with_kwargs)
    filter_keys = [param.name for param in sig.parameters.values() if param.kind == param.POSITIONAL_OR_KEYWORD]
    filtered_dict = {filter_key:dict_to_filter[filter_key] for filter_key in filter_keys}
    return filtered_dict

def myfunc(x=0):
    print(x)
mydict = {'x':2, 'y':3}
filtered_dict = filter_dict(mydict, myfunc)
myfunc(**filtered_dict) # 2
myfunc(x=3) # 3
5
Aviendha