【Python】**kwargs和takes 1 positional argument but 2 were given

时间:2024-10-30 08:10:25

Python的函数定义中可以在参数里添加**kwargs——简单来说目的是允许添加不定参数名称的参数,并作为字典传递参数。但前提是——你必须提供参数名

例如下述情况:

  1. class C():
  2. def __init__(self, **kwargs):
  3. print(kwargs)
'
运行

有如下输入:

  1. In [48]: c = C()
  2. {}
  3. In [49]: c = C(a = 1)
  4. {'a': 1}

这一切都符合常理。但是当我使用一个字典传递的时候:

  1. In [50]: c = C({'a': 1})
  2. ---------------------------------------------------------------------------
  3. TypeError Traceback (most recent call last)
  4. <ipython-input-50-2be6d5be2a84> in <module>()
  5. ----> 1 c = C({'a': 1})

我一开始以为是__init__太娇气了,换成一般办法:

  1. In [51]: class C():
  2. ...: def f(self, **kwargs):
  3. ...: print(kwargs)
  4. ...:
  5. In [52]: c = C()
  6. In [53]: ({'a': 1})
  7. ---------------------------------------------------------------------------
  8. TypeError Traceback (most recent call last)
  9. <ipython-input-53-5daee03baab1> in <module>()
  10. ----> 1 ({'a': 1})
  11. TypeError: f() takes 1 positional argument but 2 were given

包括定义在__main__下的函数也是如此:

  1. In [54]: def f1(**kwargs):
  2. ...: print(kwargs)
  3. ...:
  4. In [56]: f1({'a': 1})
  5. ---------------------------------------------------------------------------
  6. TypeError Traceback (most recent call last)
  7. <ipython-input-56-8652a6e75162> in <module>()
  8. ----> 1 f1({'a': 1})
  9. TypeError: f1() takes 0 positional arguments but 1 was given

但是当我在f1参数前加一个参数名

  1. In [57]: f1(b = {'a': 1})
  2. {'b': {'a': 1}}

问题立刻解决。

 


 

思考:

我们在先前的错误尝试中,一直传入的是个单纯的字典。虽然**kwargs提供将参数转成字典的功能,但是直接传入字典并不会使其理解成参数。实质上Python解释器认为我们输入的是作为参数值的字典,而并未携带参数名称,而Python函数机制中“固定名称”的参数应写在**kwargs的前面,因此误以为我们传入了一个“固定名称”参数,事实上我们先前的定义中并未加入“固定名称”参数,所以报错takes 1 positional arguments but 2 was given

如果真的要传入字典怎么办呢?这就简单了,直接把**kwargs改成kwargs即可:

  1. In [58]: class C():
  2. ...: def __init__(self, kwargs):
  3. ...: print(kwargs)
  4. ...:
  5. In [59]: c = C({'a': 1})
  6. {'a': 1}

这次经历使我加深了对**kwargs特殊参数的理解。以后的学习更要注意细节!