问题
This problem originated when I tried to apply a more functional approach to problems in python. What I tried to do is simply square a list of numbers, no biggie.
from operator import pow
from functools import partial
squared = list(map(partial(pow, b=2), range(10))
As it turns out, this didn't work. TypeError: pow() takes no keyword arguments
Confused I checked if pow(b=2, a=3)
did. It didn't.
I've checked the operator source code, nothing suspicious.
Confused, I've begun to doubt my own python knowledge, I made a pow function myself.
def pow(a, b):
return a ** b
Then I tried doing the same thing with my function and surprisingly, everything worked.
I'm not going to guess what is the cause of the problem, what I'm asking is simply why is this a thing and if there exists a workaround.
回答1:
If you check the signature of the built-in pow()
or operator.pow()
using the help() function in the interactive shell, you'll see that they require positional-only parameters (note the trailing slashes):
pow(x, y, z=None, /)
pow(a, b, /)
The reason is that both functions are implemented in C and don't have names for their arguments. You have to provide the arguments positionally. As a workaround, you can create a pure Python pow()
function:
def pow(a, b):
return a ** b
See also What does the slash(/) in the parameter list of a function mean? in the FAQ.
回答2:
In current versions of Python, many CPython "builtin" and standard library functions only accept positional-only parameters. The resulting semantics can be easily observed by calling the help method.
>>>>help(pow)
Help on built-in function pow in module builtins:
pow(x, y, z=None, /) Equivalent to
x**y
(with two arguments) orx**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.
The operator source code mentioned in your question may not be matching with that of the python version in which you are trying.
回答3:
The error is coming from the b=2 statement.
squared = list(map(partial(pow, b=2), range(10))
The partial function is passing the keyword parameter 'b' to the pow function, which results in an error since the pow() function takes positional arguments only. See help(pow)
for more info.
However, another issue I see with this call is that the partial function is operating in an unexpected way:
map(partial(pow, 2), range(10))
results in this sequence being generated:
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
which shows that the partial function is actually computing 2^range(10)
If what you are trying to do is square each value in a list, I would recommend simplifying the code by using a lambda function:
b=2
test = map(lambda x: x**b, range(10))
print(list(test))
which results in:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
with no imports required.
回答4:
pow as a library function accepts positional-only parameters. So here's how you could do the above:
squared = list(map(partial(pow,2), range(10)))
As for your other question, by default user defined functions' parameters are positional-or-keyword parameters, so will work both as regular or kw arguments. Of course defining a new function pow may cause confusion later down the road though so be careful.
来源:https://stackoverflow.com/questions/55970072/python-library-functions-taking-no-keyword-arguments