了解 TypeError:为关键字参数获得多个值 [英] Understanding TypeError: got multiple values for keyword argument

查看:37
本文介绍了了解 TypeError:为关键字参数获得多个值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了不同的方法来使用 *args 调用该方法.下面是我的代码片段.

def total(name, *args):如果参数:print("%s 的总金额为 Rs %d/-" %(name, sum(args)))别的:print("%s 的存钱罐没有钱" %name)

现在有两种方法可以调用这个方法.一种是在 *() 中传递额外的参数或直接用逗号分隔.我有意以 param=value 的形式传递 'name' 的值,以便它抛出我的错误.以下是我尝试的两种方法:-

1 - 传递逗号分隔的额外参数 :-

<预><代码>>>>总计(名称=阿迪",1, 2, 10 )文件<stdin>",第 1 行语法错误:关键字 arg 后出现非关键字 arg

2 - 使用 *() 传递额外的参数 :-

<预><代码>>>>总计(名称=阿迪",*(1, 2, 10))回溯(最近一次调用最后一次):文件<stdin>",第 1 行,位于 <module>类型错误:total() 为关键字参数name"获得了多个值

第一条错误消息非常清楚,它传达了确切的错误.但是,我无法理解第二次调用的错误消息.

Python 如何评估第二个调用,它为参数name"获取多个值?我想到的可能方法是 Python 在内部进行翻译

<块引用>

total(name="Adi", *(1, 2, 10) )

如下:-

<块引用>

total(*(1, 2, 10), name="Adi" )

在上面的翻译中,根据位置,'name' 获得值 *(1,2,10) 并且稍后再次获得 "Adi".所以多值错误是可以理解的.

但是,我不确定,python 内部是否会改变位置?对此的任何见解都会有所帮助.

解决方案

我使用 inspect 模块检查了该方法.来自inspect 模块的getcallargs() 方法为您提供了传递的值到方法参数的映射.

def total(name, *args):如果参数:print("%s 的总金额为 Rs %d/- "%(name, sum(args)))别的:print(%s 的存钱罐没有钱"%name)#total(name=Adi", *(1, 2, 10) )# 使用检查模块的等效调用进口检验打印 inspect.getcallargs(total, 'Adi', *(1, 2, 10) )

因此,当调用方法时,传递的所有参数都采用以下两种形式之一

<块引用>

*positional :- 所有位置参数(不带关键字)和在 *() 内传递的参数或额外的非关键字参数的元组

**named :- 以 param=value 形式传递的所有参数的字典,以及额外的关键字参数

所以在我的调用中 total(name=Adi", *(1, 2, 10) ), 'positional' 元组具有值 (1,2,10) 和 'named' 字典具有值 {'name':'Adi'}

然后它将值分配给参数.在赋值期间,强制参数首先被赋值.Python 检查强制参数列表(此处为 ['name'])并按顺序从 'positional' 元组中分配值.元组中任何未赋值的值都被假定为额外的参数(非关键字参数).

因此参数 'name' 获得分配给它的值 1.其余的值(即 2 和 10)被假定为额外的参数.

接下来,它检查方法的签名中是否有非关键字参数.如果是,则 'positional' 元组中的其余值将分配给相同的值.所以这里 'args' 被分配给剩余的值,即 (2,10) 的元组.

但是,如果方法签名中没有非关键字参数,并且 'positional' 元组仍有一些未赋值的值,那么 python 会抛出错误method requires just X arguments Y给"Y 大于 X.

一旦分配了 'positional' 中的所有值,就会分配 'named' 字典中的值.在这种情况下,解释器首先检查字典中是否存在任何强制参数,即任何强制参数的值是否以 的形式在方法中传递称呼?如果是,那么接下来它会检查在从 'positional' 元组分配值期间是否为这些强制参数分配了任何值?

如果是,那么它会为同一个参数找到两个值(一个来自 'positional',另一个来自 'named'),因此抛出 关键字参数有多个值" 错误.否则,它将值分配给 'named' 字典中的参数.

以这种方式,在上述情况下,参数 'name' 是强制性参数,并且存在于 'named' 字典中,因为我已经通过了 name=方法调用中的Adi".在分配位置值(来自 'positional' 元组的值)期间,变量 'name' 已将值 1 分配给它.并且从命名参数字典(来自 'named' 字典的值),它具有值 'Adi',这使得 2 个值被分配给变量 'name'.因此我们收到错误:-

<块引用>

total() 为关键字参数 'name' 获得了多个值

因此,在传递非关键字的额外参数时,只需要传递强制参数的值,这将使其具有位置性.但是,不是 <param=val> 的形式,这将使它命名并获得参数的两个值,因此会抛出错误.因此,不建议以 的形式传递强制参数.

所以调用该方法的正确方法是:-

<块引用>

total('Adi', *(1,2,10))

<块引用>

total('Adi', 1, 2, 10)

I was trying different ways to call the method with *args. Below is my code piece.

def total(name, *args):
    if args:
        print("%s has total money of Rs %d/- " %(name, sum(args)))
    else:
        print("%s's piggy bank  has no money" %name)

Now there are two ways to call this method. One is passing the extra arguments inside *() or directly separating by comma. I am passing value for 'name' in form of param=value, intentionally, so that it throws me error. Following are two ways I was trying :-

1 - Passing the extra params comma separated :-

>>> total(name="Adi", 1, 2, 10 )
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg

2 - Using *() to pass extra params :-

>>> total(name="Adi", *(1, 2, 10) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: total() got multiple values for keyword argument 'name'

The first error message is pretty much clear and it conveys the exact error. However, I am unable to understand the error message for the second call.

How Python is evaluating the second call that it's getting multiple values for the parameter 'name'? The possible ways that came to my mind is internally Python would be translating

total(name="Adi", *(1, 2, 10) )

as follows :-

total(*(1, 2, 10), name="Adi" )

In this above translation, as per position, 'name' gets the value *(1,2,10) and again in later it gets "Adi". So multiple values error is understood.

But, I am not sure, whether python internally would be altering the positions? Any insight on this would be helpful.

解决方案

I inspected the method using inspect module. The getcallargs() method from the inspect module, gives you the mapping of the values passed, to the arguments of the method.

def total(name, *args):
    if args:
        print("%s has total money of Rs %d/- " %(name, sum(args)))
    else:
        print("%s's piggy bank  has no money" %name)

#total(name="Adi", *(1, 2, 10) )
# equivalent call using inspect module
import inspect
print inspect.getcallargs(total, 'Adi', *(1, 2, 10) )

So, when a call to a method is made, all the arguments passed goes in either of the following two forms

*positional :- a tuple of all positional arguments (without keyword) and arguments passed within *() or the extra non-keyworded arguments

**named :- a dictionary of all the arguments passed in form of param=value, and extra keyworded arguments

So in my call total(name="Adi", *(1, 2, 10) ), 'positional' tuple has value (1,2,10) and 'named' dictionary has value {'name':'Adi'}

Then it does the assignment of the values to the arguments. During assignment, compulsory arguments are assigned first. Python checks the list of compulsory arguments (here ['name']) and assigns the value from the 'positional' tuple sequentially. Any values from the tuple left unassigned, are assumed to be extra parameters (non-keyworded arguments).

Thus the parameter 'name' gets the value 1 assigned to it. And the remaining values (i.e. 2 and 10) are assumed as extra parameters.

Next, it checks, if the method has non-keyworded arguments in it's signature. If so, then the remaining values from 'positional' tuple are assigned to the same. So here 'args' gets assigned to the remaining values i.e. tuple of (2,10).

But, if there is no non-keyword arguments in method signature, and 'positional' tuple has some values still un-assigned, then python throws the error "method takes exactly X arguments Y given" Y being greater than X.

Once all the values from 'positional' are assigned, the assignment of values from the 'named' dictionary gets assigned. In this case, interpreter first checks, if any of the compulsory arguments are present in the dictionary, i.e. if values to any of the compulsory arguments are passed in form of <param=value> in the method call? If yes, then next it checks if any value has been assigned to those compulsory arguments during the assignment of values from 'positional' tuple?

If so, then it finds two values for the same argument (one from 'positional' and the other from 'named'), and hence throws "got multiple values for keyword argument" error. Otherwise, it assigns the value to the argument from the 'named' dictionary.

In that manner, in the above case, argument 'name' is compulsory argument and is present in 'named' dictionary as I have passed name="Adi" in the method call. During assignment of positional values (values from 'positional' tuple), variable 'name' has got the value 1 assigned to it. And from the dictionary of named arguments (values from 'named' dictionary), it has go the value 'Adi', which makes 2 values being assigned to the variable 'name'. Hence we are getting the error :-

total() got multiple values for keyword argument 'name'

Therefore, while passing non-keyworded extra arguments, one needs to just pass the value for compulsory arguments, which will make it positional. But, not in form of <param=val>, which will make it named and will get two values for the parameter hence will throw the error. Therefore it is not recommended to pass the compulsory arguments in form of <param = value >.

So the correct ways to call the method are :-

total('Adi', *(1,2,10))

or

total('Adi', 1, 2, 10)

这篇关于了解 TypeError:为关键字参数获得多个值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆