0

我正在摆弄PEP 570中指定并随Python 3.8引入的仅位置参数,我只是想知道一个特定的极端情况。

假设我定义了一个函数如下(无论这是好的设计还是有任何意义):

def func(p1, p2=None, p3=None, /): 
    print(p1, p2, p3)

所以有一个必需参数 ( p1),后跟两个可选参数 (p2p3)。我可以用 just p1, p1and p2or p1and p2and来调用函数p3

func(1)       # 1, None, None
func(1, 2)    # 1, 2, None
func(1, 2, 3) # 1, 2, 3

但是我无法在保持默认 for 的同时使用p1和参数调用它,因为我无法提供关键字参数:p3p2

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, /):

所以我的问题是:这是预期的行为,让调用者从左到右提供多个可选参数,以强制顺序覆盖它们吗?这实际上是仅位置参数的一个特征吗?

4

2 回答 2

0

一个让我感到困惑的确切描述行为的一个很好的例子是evalBuiltin,它有两个仅位置可选参数:

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

所以,回答这个问题:这正是预期的行为。

于 2019-10-31T10:48:23.130 回答
0

这是预期的行为,让调用者从左到右提供多个可选参数,以强制顺序覆盖它们吗?这实际上是仅位置参数的一个特征吗?

这不仅是位置参数的“预期行为”,而且几乎是它的定义。

func(1, p3=3)直接与函数签名中的使用相矛盾,/因为它为只接受位置参数的函数提供了关键字参数。具有默认值的事实p2是无关紧要的(尽管您发现它几乎没有用)。

我将继续在文档中寻找明确的解释,但可能没有。这基本上是使用/.

但是PEP570 包含此示例

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

在线尝试

于 2019-10-30T09:12:36.127 回答