当help()列出方法签名时,斜杠代表什么意思?

286

在Python 3.4的range函数的help输出中,括号结束之前的/代表什么意思?

>>> help(range)
Help on class range in module builtins:

class range(object)
 |  range(stop) -> range object
 |  range(start, stop[, step]) -> range object
 |  
 |  Return a virtual sequence of numbers from start to stop by step.
 |  
 |  Methods defined here:
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  
 |  __eq__(self, value, /)
 |      Return self==value.

                                        ...
3个回答

309

它表示仅限位置参数的结束,这些参数您不能用作关键字参数。在Python 3.8之前,只能在C API中指定这样的参数。

这意味着 __contains__ key 参数只能通过位置传递( range(5).__ contains__(3)),而不能作为关键字参数传递( range(5).__ contains__(key = 3)),纯Python函数的位置参数可以这样做。

另请参见Argument Clinic文档:

要在Argument Clinic中将所有参数标记为仅限位置,请在最后一个参数后面的单独一行上添加/,缩进与参数行相同。

以下是关于 Python FAQ 的最新更新:

函数参数列表中的斜杠表示它前面的参数是位置参数。位置参数是没有外部可用名称的参数。在调用接受位置参数的函数时,参数仅基于它们的位置映射到参数。

该语法现已成为 Python 语言规范的一部分,截至版本3.8, 请参见 PEP 570 - Python Positional-Only Parameters。在 PEP 570 之前,该语法已被保留以便未来可能包含在 Python 中,请参见 PEP 457 - Syntax For Positional-Only Parameters

位置参数可使API更加清晰易懂,使纯Python实现的原本只有C才能实现的模块更加一致和易于维护,并且因为位置参数需要很少的处理,所以它们可以导致更快的Python代码。

9
有趣的副作用是,位置参数的名称不会与 **kwargs 冲突,这对于函数式编程或修饰函数时装饰器参数名称可能会与被修饰函数参数冲突的情况非常有用。 - hugovdberg
1
@MarcosPereira:问题要求回答“什么”:“help()输出中的斜杠是什么意思?” - Martijn Pieters
“为什么”是一个完全不同的问题(我从未见过一个完全令人信服的答案)。 - chepner
2
@hugovdberg:我有一段时间很困惑,但你是在谈论delay_call2()签名中的func 参数,因为第50行的调用可以工作,因为func(关键字)参数不会与func参数冲突。是的,这是语法的一个愉快的副作用,在此之前,您必须使用*args并从中解包分配给func参数的参数。通常:函数签名中的名称是参数,调用表达式中传递的值是参数。这样更容易谈论两侧调用中使用的语法。 - Martijn Pieters
2
@hugovdberg: 我之前有点困惑,但你是在谈论delay_call2()函数签名中的func 参数,在第50行的调用中,func(关键字)参数不会与func参数冲突。是的,这是语法的一个愉快的副作用,在以前,你必须使用*args并从中解包分配给func参数的参数。一般来说:函数签名中的名称是参数,调用表达式中传递的值是参数。这样更容易讨论调用两边使用的语法。 - undefined
显示剩余4条评论

93

我自己也问过这个问题。:) 发现 / 最初是由 Guido 在 这里 提出的。

  

替代建议:使用 '/'如何?它有点相反   '*' ,它表示“关键字参数”,而 '/' 不是新字符。

然后他的提议胜利了

  

嘿,如果这是真的,那么我的'/'提案获胜:

 def foo(pos_only, /, pos_or_kw, *, kw_only): ...
我认为相关的文档是 PEP 570,其中总结部分看起来很好。

总结

使用情况将决定函数定义中使用哪些参数:

 def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):

指导意见:

如果参数名称不重要或无意义,并且只有少量参数将始终按相同顺序传递,则使用位置参数。 当名称具有意义且函数定义通过明确名称更易于理解时,请使用关键字参数。

def foo(p1, p2, /)
这意味着所有的函数参数都是按位置传递的。

这意味着所有的函数参数都是按位置传递的。


42
选择使用 / 标记,因为“它是 * 的反操作”,这表明 Python 有点疯狂。这是一种类比感觉。 - Tomasz Gandor
2
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2) 是确保记住...记住什么?不是参数,不是关键字,不是运算符...啊,在 PEP 里也有...两者标记。至少如果你记得引入这些标记之前标准参数是“pos_or_kwd”。 - mins
+1 对 def foo(pos_only, /, pos_or_kw, *, kw_only),简单解释了 /*由Guido在参数中使用的一对逆算术运算符 —(可选地)将参数列表分为(最多)三个部分。 - SnzFor16Min

38

斜杠(/)表示其前面的所有参数都是位置参数。在 Python 3.8 中添加了位置参数特性,此前 PEP 570 被接受。最初,这种符号是在 PEP 457 - Notation For Positional-Only Parameters 中定义的。

函数定义中斜杠(/)之前的参数是位置参数,而斜杠(/)后面的参数可以是任何类型,根据语法来确定。在调用函数时,参数仅基于它们的位置映射到位置参数。通过关键字(名称)传递位置参数是无效的。

让我们看下面的例子:

def foo(a, b, / , x, y):
   print("positional ", a, b)
   print("positional or keyword", x, y)

在上面的函数定义中,参数a和b是位置参数,而x或y可以是位置参数或关键字参数。
以下函数调用是有效的。
foo(40, 20, 99, 39)
foo(40, 3.14, "hello", y="world")
foo(1.45, 3.14, x="hello", y="world")

但是,以下函数调用无效,会引发TypeError异常,因为a、b不是作为位置参数传递,而是作为关键字传递

foo(a=1.45, b=3.14, x=1, y=4)

类型错误:foo() 作为关键字参数传递了一些位置参数:'a, b'

Python 中许多内置函数接受仅限位置参数,其中通过关键字传递参数没有意义。例如,内置函数 len 仅接受一个位置(仅限)参数,调用 len(obj="hello world") 会影响可读性,请查看 help(len)。

>>> help(len)
Help on built-in function len in module builtins:

len(obj, /)
    Return the number of items in a container.

仅位置参数使底层的C库函数容易维护。它允许在将来更改仅位置参数的参数名称,而不会破坏使用API的客户端代码。

最后但并非最不重要的是,仅位置参数允许我们在可变长度关键字参数中使用它们的名称。请查看以下示例:

>>> def f(a, b, /, **kwargs):
...     print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3)         # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}

Python3.8正式添加了位置参数语法。请查看Python3.8的新特性-仅限位置参数

PEP相关:PEP 570 -- Python位置参数仅限


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