Неожиданный аргумент в Python

Использую классовый подход с наследованием и динамическим выбором методов. Аргументы в методы передаю через словари.

Получаю такую ошибку:

method got an unexpected keyword argument keyword

Пример: def test(a). Я вызываю как: test(a=1, b=2) b - неожиданный аргумент.

Причина как-бы понятна. Понимаю, что можно в методы вписать:

  • * - Для сбора в кортежи.
  • ** - Для сбора в списки.

А игнорировать эти аргументы как-то можно, если нет смысла их собирать. Или лучше позаботится, чтобы в словаре при раскладывании "лишних" аргументов не было?

P.S Суть в том, что методы вызываются динамически, в зависимости от входных параметров, и аргументы прилетают тоже динамически. Мне, чтобы это убрать нужно хранить список всех аргументов методов где-то. Или использовать сбор таких параметров в методах. Есть еще варианты?


Ответы (3 шт):

Автор решения: Xander
def strict(a=1):
    print(a)


def flexible(**kwargs):
    a = kwargs.get('a')
    print(a)
    

args = dict(a=1, b=2)


strict(**args)  # Ошибка
flexible(**args)  # Нет ошибки, "b" просто проигнорируется
→ Ссылка
Автор решения: asanisimov

* и ** как операторы-префиксы используются для распаковки итерируемых объектов и словарей, соответственно. И для захвата аргументов переданных в функцию.

Касательно вашего примера

def test(a):
   pass

test(a=1, b=2) 

Выдаст ошибку, так как функция ожидает только 1 аргумент, а вы передаете неизвестный именованный аргумент, о чем ошибка Вам и сообщает.

Если кол-во входящих параметров неизвестны, то используются выше указанные операторы. как пример:

def test(*args, **kwargs):
    for i in args:
        print(i)
    for k, v in kwargs.items():
        print(f'{k}-{v}')

В такую функцию можно передавать сколь угодно параметров.

test(1,2,3, a=4, b=5)
# Out
1
2
3
a-4
b-5

Можно совмещать с ожидаемымси параметрами.

def test(arg1, *args, **kwargs):
    print(f'this is arg1 {arg1}')
    for i in args:
        print(i)
    for k, v in kwargs.items():
        print(f'{k}-{v}')
#out
this is arg1 1
2
3
a-4
b-5

Так же операторы можно использовать для распаковки аргументов. * - любой итерируемый объект. ** - словарь.

print(*(1, 2, 3)) # 1 2 3
print(*[1, 2, 3]) # 1 2 3
print(*{1, 2, 3}) # 1 2 3
print(*{1: 2, 2: 2, 3: 3}) # 1 2 3

Этим можно пользоваться при передачи параметров в функцию.

dict_args = {
    "arg1": 25,
    "arg2": 100
}


def test(arg1, arg2):
    print(arg2-arg1)

test(**dict_args) # 75

→ Ссылка
Автор решения: insolor

Как вариант, каждому методу кроме нужных ему параметров добавить параметр с двумя звездочками **, тогда все "лишние" именованные параметры будут попадать в этот параметр:

def test(a, **_):
   pass


test(a=1, b=2)
args = dict(a=1, b=2)
test(**args)  # Так тоже будет работать
→ Ссылка