Как игнорировать неожиданные аргументы ключевого слова, переданные функции?

Предположим, у меня есть какая-то функция, f:

def f (a=None):
    print a

Теперь, если у меня есть словарь, такой как dct = {"a":"Foo"}, я могу вызвать f(**dct) и получить результат Foo.

Однако предположим, что у меня есть словарь dct2 = {"a":"Foo", "b":"Bar"}. Если я позвоню f(**dct2) я получу

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

Справедливо. Однако в любом случае, в определении f или при вызове его, Python должен просто игнорировать любые ключи, которые не являются именами параметров? Предпочтителен метод, который позволяет указывать значения по умолчанию.

Ответы

Ответ 1

В качестве дополнения к ответу, опубликованному @Bas, я бы предложил добавить аргументы kwargs (аргументы ключевого слова переменной длины) в качестве второго параметра функции

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


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

Это обязательно будет достаточно в случае

  1. просто игнорировать любые ключи, которые не являются именами параметров
  2. Тем не менее, ему не хватает значений параметров по умолчанию, что является хорошей особенностью, которую было бы неплохо сохранить

Ответ 2

Это можно сделать, используя **kwargs, который позволяет собирать все аргументы ключевого слова undefined в файле dict:

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

Быстрый тест:

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

EDIT Если вы все еще хотите использовать аргументы по умолчанию, вы сохраняете исходный аргумент со значением по умолчанию, но вы просто добавляете **kwargs для поглощения всех остальных аргументов:

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

Ответ 3

Если вы не можете изменить определение функции для получения неуточненных ** kwargs, вы можете отфильтровать словарь, который вы передаете с помощью аргументов ключевого слова, используя функцию argspec в более старых версиях python или метод проверки подписи в 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