英文:
Asking a detailed guideline to forece parameters as positional-only, positional- or keyword-argument, and keyword only when using *args and **kwargs
问题
https://docs.python.org/3/tutorial/controlflow.html#special-parameters
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
根据文档,/ 和 * 表示参数的类型,根据参数如何传递给函数来决定:仅位置参数、位置或关键字参数以及仅关键字参数。
在使用普通位置参数或关键字参数时,如何使用是明显的。但是,当与 *args 或 **kwargs 一起使用时,对我来说变得很复杂。
例如,
def func(a, *args, /): # SyntaxError: / must be ahead of *
pass
这段代码引发了 SyntaxError: / must be ahead of *,尽管很明显 a 和 args 是位置参数。我知道这里不需要 /,但我想知道错误消息为什么是 SyntaxError: / must be ahead of *。我使用 * 来指出 *args,而不是独立的 *。
def func(a, /, *args): # No error!?
pass
然而,这段代码却可以正常工作,尽管 *args 被指定为位置或关键字参数,因为它跟随在 / 之后(*args 不能接受关键字参数!)。我认为这应该引发错误,如 SyntaxError: *args cannot take keyword argument。
此外,
def func(*, **kwargs): # SyntaxError: named arguments must follow bare *
pass
这段代码引发了 SyntaxError: named arguments must follow bare *。我知道在函数中 * 是不必要的,但错误消息说命名参数必须跟在裸 * 后面,尽管命名参数 **kwargs 已经跟在 * 后面了。
我觉得我可能遗漏了某些内容。因此,如果有人能更详细地解释如何在使用 *args 或 **kwargs 时使用 / 和 *,将不胜感激。
英文:
https://docs.python.org/3/tutorial/controlflow.html#special-parameters
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
According to the reference, / and * indicate the kind of parameter by how the arguments may be passed to the function: positional-only, positional-or-keyword, and keyword-only.
It is clear how to use it when I use normal positional arguments or keyword arguments. However, when I use *args or **kwargs together, it becomes very complicated to me.
for example,
def func(a, *args, /): # SyntaxError: / must be ahead of *
pass
This code raise SyntaxError: / must be ahead of * although it is clear that a and args is positional parameters. I know / is unnecessary here, but what I am wondering is why the Error message is SyntaxError: / must be ahead of *. I used * for to point out *args, not independent *.
def func(a, /, *args): # No error!?
pass
However, this code works without Error although *args is indicated as positioal- or keyword- arguments as it follows / (*args cannot take keyword arguments!). I think this should raise Error such as SyntaxEror: *args cannot take keyword argument.
In addition,
def func(*, **kwargs): # SyntaxError: named arguments must follow bare *
pass
This code raise SyntaxError: named arguments must follow bare *. I know in the function, * is unnecessary, but the error message says named arguments must follow bare * although the named arguments **kwargs is already following *.
I think I am missing something. So, it would very appreciate if anyone explain more detailed guideline to use / and * when using *args or **kwargs.
答案1
得分: 1
以下是您要翻译的内容:
答案非常简单:错误消息看起来很奇怪,但实际上工作与不工作是非常合乎逻辑的。
请记住,如果您同时使用制表符和空格的混合,可能会出现“错误:无效常数”。解析器并不总是能够明白为什么某些东西不起作用。此外,您对“/”的工作原理有一些误解。
*args 接受所有位置参数
**kwargs 接受所有关键字参数。
因此,如果您定义一个这样的函数:
def func(a, *args, /): # 语法错误:/ 必须在 * 之前
pass
您实际上做了相同的事情。/ 禁止了更多的位置参数,但 *args 已经接受了所有位置参数,所以斜杠是不必要的。
对于 *, **kwargs 也是一样的。* 不是必需的。
但是,以下代码可以工作:
def hello(*, hello: str = "Hello", **kwargs):
print(kwargs)
在这种情况下,需要使用 *,否则 hello 可以被按位置传递。因此,这也可以工作。解析器只检查是否存在一个定义来接受 * 后面的变量,而 **kwargs 不包含这一点,这不被视为错误,因为没有必要以这种方式使用它。
最后,我同意这样的代码:
def func(a, /, *args): # 没有错误!?
pass
很奇怪,但它确实可以工作:
/ 禁止将任何东西放在它前面作为关键字传递,而 * 要求在它后面接受关键字。您可以在 / 后面传递位置参数,*args 会接受它们。
这是完全有效的 Python 代码:
def hello(a, /, *args):
print(args)
print(a)
hello("a", "b")
>>> ('b',)
>>> a
因此,这是顺序:
(位置参数, 仅位置, /, 位置或关键字, [*args或*], 仅关键字, **kwargs)
如果您指定了 * 然后是 **kwargs,而没有其他内容,它会引发额外的错误,因为不需要 *。
您收到的错误消息确实有点奇怪,但一切都是合理的。
希望这对您有所帮助。 ![]()
英文:
The answer to this question is really simple: The error messages are weird, however, what works and what does not is really logical.
Keep in mind that, if you are using a mixture of tabs and spaces, you can get an error: invalid constant. The parser is not always able to see why something does not work. Also, you kind of misunderstand how / works.
*args eats up all positional arguments
**kwargs eats up all keyword arguments.
So, if you define a function like this:
def func(a, *args, /): # SyntaxError: / must be ahead of *
pass
You're doing the same thing twice. / prohibits any more locational arguments, but *args already eats up all of them, so the slash is not needed.
Same goes for *, **kwargs. * just not needed.
This, however, does work:
def hello(*, hello: str = "Hello", **kwargs):
print(kwargs)
At this point, the * is needed, as otherwise hello could be passed positionally. This, therefore also works. The parser just checks if there is a definition to take variables after the *, and **kwargs does not, and this is not seen as a bug, because there is no need to use it that way.
Lastly, I agree that this:
def func(a, /, *args): # No error!?
pass
Is weird code, but it does work:
the / prohibits anything in front of it to be passed as a keyword, and * mandates anything after it to be taken as a keyword. You can pass positional arguments after a /, and *args will eat those up.
This is perfectly valid python:
def hello(a, /, *args):
print(args)
print(a)
hello("a", "b")
>>> ('b',)
>>> a
So, this is the order:
(positional, only, /, positional or keyword, [*args or *], keyword only, **kwargs)
Where, if you specify a * and then **kwargs without anything in between, it throws an additional error, because the * was not needed.
The error messages you get are indeed a bit weird, but it does all check out.
I hope that helps. ![]()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论