Python 请解释为什么传入关键字参数时这两个内置函数的行为不同
考虑这些不同的行为:Python 请解释为什么传入关键字参数时这两个内置函数的行为不同,python,Python,考虑这些不同的行为: >> def minus(a, b): >> return a - b >> minus(**dict(b=2, a=1)) -1 >> int(**dict(base=2, x='100')) 4 >> import operator >> operator.sub.__doc__ 'sub(a, b) -- Same as a - b.' >> operator.sub(**
>> def minus(a, b):
>> return a - b
>> minus(**dict(b=2, a=1))
-1
>> int(**dict(base=2, x='100'))
4
>> import operator
>> operator.sub.__doc__
'sub(a, b) -- Same as a - b.'
>> operator.sub(**dict(b=2, a=1))
TypeError: sub() takes no keyword arguments
为什么operator.sub
的行为与int(x,[base])
不同?减号(**dict(b=2,a=1))
扩展为减号(b=2,a=1)
。这是因为您的定义有参数名a
和b
operator.sub(**dict(b=2,a=1))
扩展为operator.sub(b=2,a=1)
。这不起作用,因为sub不接受关键字参数。这是一个实现细节。位置参数和关键字参数之间的分隔。位置参数内部甚至没有名称
用于检索运算符的参数的代码。add
函数(以及类似的sub
)如下所示:
PyArg_解包元组(a,#OP,2,2,&a1,&a2)
如您所见,它不包含任何参数名称。与操作员添加相关的整个代码是:
#定义spam2(OP,AOP)静态PyObject*OP(PyObject*s,PyObject*a){\
PyObject*a1、*a2\
如果(!PyArg_unpactuple(a,#OP,2,2,&a1,&a2))返回NULL\
返回AOP(a1,a2);}
spam2(op_add,PyNumber_add)
#定义spam2(OP,ALTOP,DOC){#OP,OP###OP,METH_VARARGS,PyDoc_STR(DOC)}\
{#ALTOP,op###op,METH#u VARARGS,PyDoc#u STR(DOC)},
spam2(添加,添加,添加,添加(a,b)--与a+b.相同)
如您所见,使用a
和b
的唯一位置是docstring。方法定义也不使用METH_KEYWORDS
标志,这是方法接受关键字参数所必需的
一般说来,您可以安全地假设一个基于python的函数,如果您知道一个参数名,它将始终接受关键字参数(当然,有人可能会用*args
解包,但创建一个参数看起来正常的函数文档)而C函数可能接受也可能不接受关键字参数。具有多个参数或可选参数的函数很可能接受后面的/可选参数的关键字参数。但你几乎必须测试它
您可以在网站上找到关于支持关键字参数的讨论。Guido van Rossum(又名Python的创建者)对此也有一句话:
嗯。我认为对于许多(大多数?)1-arg和选定的2-arg函数(以及
很少有3+-arg函数)这会降低可读性,例如
显示了ord(字符=x)的数量
实际上,我希望看到一个语法特性来说明
参数不能作为关键字参数提供(正如我们已经做的那样)
添加了语法以说明它必须是关键字)
我认为添加关键字args是完全错误的:方法
内置类型或ABC的,可重写的。例如考虑
dict.上的pop()方法,因为参数名称当前为
未记录,如果有人将dict子类化并重写此方法,或
如果他们创建另一个尝试模拟的可变映射类
dict使用duck类型,参数名是什么并不重要--
所有调用方(应为dict、dict子类或类似dict
duck)将在调用中使用位置参数。但如果我们是
记录pop()的参数名称,用户开始使用
这些,然后大多数dict子机箱和鸭子会突然被打破
(除非他们碰巧取了同一个名字)
操作符
是一个C模块,它。除非模块初始化中的函数声明包括METH\u关键字
,该函数在任何情况下都不会接受关键字参数,您会得到问题中给出的错误。我很确定他在问为什么它不接受关键字参数,而您没有回答。您是说operator.sub的参数名为减?@BonAmi:没错operator.sub
的参数为nameless@Eric所以int
不是在C中实现的吗?我该怎么查?@BonAmi:不知道你能不能查到<我的第一个猜测是code>inspect.getargspec
,但C函数中存在错误。非常确定int
是用C实现的,但是带有显式命名的参数。如果人们也能回答为什么这个函数选择不使用关键字参数,那就太好了,我也想知道这一点:关于风格选择,我应该指出,接受关键字参数会增加函数调用的开销,如果用户实际上通过关键字将参数传递给内置函数,则开销会显著增加。Python 3.5中的微基准表示int(“0”,2)
vs.int(“0”,base=2)
在我的机器上运行后者需要约2.5倍的时间;解析参数花费的时间比实际工作花费的时间要多。更糟糕的是函数只使用一个参数,这有一个避免参数包装的快速路径,但移动到关键字意味着参数必须包装在元组和/或dict
中。