Python 3.8 中只有位置参数的极端情况?
Corner case with positional-only parameters in Python 3.8?
我正在摆弄 PEP 570 and introduced with Python 3.8 中指定的仅位置参数,我只是想知道一个特定的极端情况。
假设我按如下方式定义了一个函数(无论这是好的设计还是有意义):
def func(p1, p2=None, p3=None, /):
print(p1, p2, p3)
所以有一个必需参数(p1
),后面跟着两个可选参数(p2
和p3
)。我可以只用 p1
、p1
和 p2
或 p1
和 p2
和 p3
:
调用函数
func(1) # 1, None, None
func(1, 2) # 1, 2, None
func(1, 2, 3) # 1, 2, 3
但是我无法只用 p1
和 p3
的参数来调用它,同时保持 p2
的默认值,因为我无法提供关键字参数:
func(1, p3=3)
这当然会引发TypeError
:
TypeError: func() got some positional-only arguments passed as keyword arguments: 'p3'
我找不到关于这种情况的任何讨论或示例,因为 PEP 570 中的所有示例仅包含一个可选参数作为仅位置参数的一部分:
def name(p1, p2, /, p_or_kw, *, kw):
def name(p1, p2=None, /, p_or_kw=None, *, kw):
def name(p1, p2=None, /, *, kw):
def name(p1, p2=None, /):
def name(p1, p2, /, p_or_kw):
def name(p1, p2, /):
所以我的问题是:这是预期的行为,让调用者从左到右提供多个可选参数,以强制顺序覆盖它们吗?这实际上是仅位置参数的一个特征吗?
Is that the intended behavior, to have a caller provide multiple optional arguments from left to right, overriding them in a forced order? Is this actually a feature of positional-only arguments?
不仅是位置参数的 "intended behavior",它几乎就是位置参数的定义。
func(1, p3=3)
与函数签名中 /
的使用直接矛盾,因为它为仅接受位置参数的函数提供关键字参数。 p2
有一个默认值这一事实是无关紧要的(尽管它几乎没有用,就像你发现的那样)。
我会继续在文档中寻找明确的解释,但可能没有。这基本上是使用 /
.
的直接暗示
不过,PEP570 includes this example:
def name(positional_only_parameters, /, positional_or_keyword_parameters,
*, keyword_only_parameters):
这表明我们可以将 func
重写为:
def func(p1,p3=None, /, p2=None):
print(p1, p2, p3)
那么这两个都有效:
func(1, 3)
func(1, 3, 2)
输出为
1 None 3
1 2 3
eval
内置函数是描述让我感到困惑的行为的一个很好的例子,它有两个仅限位置的可选参数:
eval(source, globals=None, locals=None, /)
Evaluate the given source in the context of globals and locals.
The source may be a string representing a Python expression
or a code object as returned by compile().
The globals must be a dictionary and locals can be any mapping,
defaulting to the current globals and locals.
If only globals is given, locals defaults to it.
所以无法指定只有 locals
:
>>> eval("1 + 2 + x", locals={'x': 3})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: eval() takes no keyword arguments
在位置上,必须先提供globals
(如果省略locals
,它们默认为globals
):
>>> eval("1 + 2 + x", {'x': 3}) # globals = locals
6
... 或者,如果它们应该不同:
>>> eval("1 + 2 + x", {'x': 3}, {'x': 4})
7
所以,回答这个问题:这正是预期的行为。
我正在摆弄 PEP 570 and introduced with Python 3.8 中指定的仅位置参数,我只是想知道一个特定的极端情况。
假设我按如下方式定义了一个函数(无论这是好的设计还是有意义):
def func(p1, p2=None, p3=None, /):
print(p1, p2, p3)
所以有一个必需参数(p1
),后面跟着两个可选参数(p2
和p3
)。我可以只用 p1
、p1
和 p2
或 p1
和 p2
和 p3
:
func(1) # 1, None, None
func(1, 2) # 1, 2, None
func(1, 2, 3) # 1, 2, 3
但是我无法只用 p1
和 p3
的参数来调用它,同时保持 p2
的默认值,因为我无法提供关键字参数:
func(1, p3=3)
这当然会引发TypeError
:
TypeError: func() got some positional-only arguments passed as keyword arguments: 'p3'
我找不到关于这种情况的任何讨论或示例,因为 PEP 570 中的所有示例仅包含一个可选参数作为仅位置参数的一部分:
def name(p1, p2, /, p_or_kw, *, kw):
def name(p1, p2=None, /, p_or_kw=None, *, kw):
def name(p1, p2=None, /, *, kw):
def name(p1, p2=None, /):
def name(p1, p2, /, p_or_kw):
def name(p1, p2, /):
所以我的问题是:这是预期的行为,让调用者从左到右提供多个可选参数,以强制顺序覆盖它们吗?这实际上是仅位置参数的一个特征吗?
Is that the intended behavior, to have a caller provide multiple optional arguments from left to right, overriding them in a forced order? Is this actually a feature of positional-only arguments?
不仅是位置参数的 "intended behavior",它几乎就是位置参数的定义。
func(1, p3=3)
与函数签名中 /
的使用直接矛盾,因为它为仅接受位置参数的函数提供关键字参数。 p2
有一个默认值这一事实是无关紧要的(尽管它几乎没有用,就像你发现的那样)。
我会继续在文档中寻找明确的解释,但可能没有。这基本上是使用 /
.
不过,PEP570 includes this example:
def name(positional_only_parameters, /, positional_or_keyword_parameters,
*, keyword_only_parameters):
这表明我们可以将 func
重写为:
def func(p1,p3=None, /, p2=None):
print(p1, p2, p3)
那么这两个都有效:
func(1, 3)
func(1, 3, 2)
输出为
1 None 3
1 2 3
eval
内置函数是描述让我感到困惑的行为的一个很好的例子,它有两个仅限位置的可选参数:
eval(source, globals=None, locals=None, /)
Evaluate the given source in the context of globals and locals.
The source may be a string representing a Python expression
or a code object as returned by compile().
The globals must be a dictionary and locals can be any mapping,
defaulting to the current globals and locals.
If only globals is given, locals defaults to it.
所以无法指定只有 locals
:
>>> eval("1 + 2 + x", locals={'x': 3})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: eval() takes no keyword arguments
在位置上,必须先提供globals
(如果省略locals
,它们默认为globals
):
>>> eval("1 + 2 + x", {'x': 3}) # globals = locals
6
... 或者,如果它们应该不同:
>>> eval("1 + 2 + x", {'x': 3}, {'x': 4})
7
所以,回答这个问题:这正是预期的行为。