class Klass:
  def __init__(self, **kwargs):
    self.func(variable=True, **kwargs)

  def func(self, variable=True, **kwargs):
    print(variable)


if __name__ == '__main__':
  Klass(variable=False)

Мне было интересно, почему я получаю TypeError: func() got multiple values for keyword argument 'variable'.

Я думаю, он должен напечатать False, потому что я переопределяю значение по умолчанию variable на False и передаю kwargs по пути.

2
Zizheng Wu 21 Авг 2018 в 04:53

4 ответа

Лучший ответ

Вы не можете передать один и тот же аргумент дважды, и variable=True, **kwargs делает именно это, когда kwargs содержит ключ для variable; в этом случае вы сделали эффективный вызов self.func(variable=True, variable=False), что явно неверно. Предполагая, что вы не можете получить variable в качестве отдельного аргумента, например:

def __init__(self, variable=True, **kwargs):
    self.func(variable, **kwargs)

Тогда другой подход - установить значение по умолчанию в самом kwargs dict:

def __init__(self, **kwargs):
    kwargs.setdefault('variable', True)  # Sets variable to True only if not passed by caller
    self.func(**kwargs)

В Python 3.5 с дополнительными обобщениями для распаковки PEP 448 вы можете в одну строку это безопасно как:

def __init__(self, **kwargs):
    self.func(**{'variable': True, **kwargs})

Поскольку повторные ключи допустимы при создании нового dict (сохраняется только последнее вхождение ключа), поэтому вы можете создать новый dict с уникальными сопоставлениями, а затем сразу же распаковать его.

11
ShadowRanger 21 Авг 2018 в 02:01

Когда вы объявляете объект класса Klass,

Klass(variable=False)

variable анализируется как аргумент ключевого слова (kwargs), который в любом случае является dict. Так что внутри метода __init__ вы можете найти kwargs

{'variable': False'}

И в

self.func(variable=True, **kwargs)

Двойная звездочка подразумевает синтаксический анализ всего в dict в качестве аргументов ключевого слова. Технически эта линия равна

self.func(variable=True, **{'variable': False'})

И равно

self.func(variable=True, variable=False)

И вот почему вы получили TypeError.

Вот, вероятно, то, что вы ищете:

class Klass:
  def __init__(self, **kwargs):
    self.func(**kwargs)

  def func(self, variable=True, **kwargs):
    print(variable)

if __name__ == '__main__':
  Klass(variable=False)
0
K.Marker 21 Авг 2018 в 02:08

Потому что вы вводите переменные аргументы, поэтому python не знает, что правильно, поэтому возникает ошибка

Более понятный пример:

>>> class A:
    def __init__(self):
        self.f(a=4,a=5)
    def f(self,a):
        return a

SyntaxError: keyword argument repeated
>>> 
0
U10-Forward 21 Авг 2018 в 01:57
class Klass:
  def __init__(self, **kwargs):
    self.func(**kwargs)

  def func(self, variable=True, **kwargs):
    print(variable)


if __name__ == '__main__':
  Klass(variable=False)

Это должно работать. Вы устанавливаете значение по умолчанию «True» и передаете параметр «False» одному ключевому слову «variable».

0
Willtunner 21 Авг 2018 в 02:01
51940581