Python库函数不接受关键字参数。

9
这个问题是在我尝试以更加函数式的方式解决Python问题时产生的。我尝试的是简单地对一组数字进行平方,没什么大不了的。
from operator import pow
from functools import partial 

squared = list(map(partial(pow, b=2), range(10))

事实证明,这样做行不通。 TypeError: pow() takes no keyword arguments 混淆不解,我检查了pow(b=2, a=3)是否可行,但它并不可行。
我检查了operator源代码,没有发现可疑的地方。
感到困惑,我开始怀疑自己的Python知识,于是自己编写了一个pow函数。
def pow(a, b):
  return a ** b

然后我尝试用我的函数做同样的事情,出人意料的是一切都正常了。

我不想猜测问题的原因,我只是在问为什么会有这种情况,并且是否存在解决方法。


1
这是因为C代码没有编写支持关键字参数的功能。至于解决方法,创建一个包装函数(或自己的pow())就是解决方法。 - Wolph
2
你可以使用 list(map(mul, *itertools.tee(range(10)))),但这只适用于 pow(x, 2),对于一般情况没有任何作用。 - tobias_k
顺便提一下,Python 有一个PEP 457草案来实现这个功能,所以你也可以创建自己的位置参数。 - Jeyekomon
请注意,在Python 3.8中,内置函数pow()现在接受关键字参数,因为它的签名变成了pow(base, exp, mod=None) - AChampion
4个回答

6

如果你在交互式shell中使用help()函数检查内置的pow()operator.pow()的签名,你会发现它们需要仅限位置参数(注意末尾的斜杠):

pow(x, y, z=None, /)
pow(a, b, /)

原因在于这两个函数都是用C实现的,并且没有为它们的参数命名。您必须按位置提供参数。作为解决方法,您可以创建一个纯Python的pow()函数:

def pow(a, b):
    return a ** b

请参见FAQ中关于参数列表中斜线(/)的含义的解释


在这种情况下,由于functools.partial的工作方式,解决方法是使用:list(map(partial(pow, 2), range(10))) - Jon Clements
1
@Wolph 是的...但这同样是不正确的... :) - Jon Clements
@Welperooni:如果有帮助的话,你可以在这里找到operator的C版本源代码链接 - Eugene Yarmash
除非squared = list(map(pow, range(10), itertools.repeat(2)))算作... - Jon Clements
@EugeneYarmash 谢谢,但你能提供实际的Python源代码链接吗?我至少想证明我的说法是错误的。 - Welperooni
显示剩余7条评论

2
在当前版本的Python中,许多CPython“内置”和标准库函数只接受位置参数。可以通过调用help方法轻松观察到结果语义。

>>>>help(pow)

Help on built-in function pow in module builtins:

pow(x, y, z=None, /) Equivalent to x**y (with two arguments) or x**y % z (with three arguments)

Some types, such as ints, are able to use a more efficient algorithm when
invoked using the three argument form.

你问题中提到的操作符源代码可能与你正在尝试的Python版本不匹配。


1

错误来自 b=2 语句。

squared = list(map(partial(pow, b=2), range(10))

部分函数将关键字参数“b”传递给pow函数,这会导致错误,因为pow()函数仅接受位置参数。有关更多信息,请参见help(pow)
但是,我看到这个调用的另一个问题是部分函数以意外的方式运作:
map(partial(pow, 2), range(10))

导致生成以下序列:
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

这说明部分函数实际上正在计算2的10次方。
如果您想做的是将列表中的每个值平方,我建议使用lambda函数简化代码:
b=2
test = map(lambda x: x**b, range(10))
print(list(test))

这句话的意思是:“导致了以下结果:”。
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

不需要任何导入。


-1

pow作为一个库函数,接受位置参数。以下是实现上述功能的方法:

squared = list(map(partial(pow,2), range(10)))

关于您的另一个问题,用户定义函数的参数默认为 位置或关键字参数,因此可以作为常规参数或关键字参数使用。当然,定义一个新函数 pow 可能会导致稍后的混淆,请小心。

1
那应该是 pow(2, n),而不是 pow(n, 2) - tobias_k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接