Python函数签名中的星号 * 和斜杠 / 的作用

1. 星号 *

作用:表示星号后的参数必须通过关键字传递(Keyword-Only),不能按位置传递。

示例:

1
2
3
4
5
def func(a, *, b, c):
    print(a, b, c)

func(1, b=2, c=3)  # 正确:b、c必须是关键字参数
func(1, 2, 3)      # 错误:b、c不能按位置传递

用途:强制提高代码可读性,或确保某些参数显式命名。

发展历史

详见 PEP3102 文档(2006年):PEP 3102 – Keyword-Only Arguments

在 PEP3102 之前,函数支持位置参数和关键字参数,以及可变位置参数和可变关键字参数。

但是这有一定的限制,比如:

  1. 所有的常规参数必须放在可变参数之前。
  2. 如果我们想同时使用可变位置参数和若干关键字参数,则只能使用 *args, **args 的形式来接收,然后自行解构 **args**

在 PEP3102 之后,有两点语法上的改变。

  1. 可以在可变参数之后使用常规参数。
1
2
def sortwords(*wordlist, case_sensitive=False):
    ...

这个函数可以接收任意个位置参数,和一个可选的关键字参数。

这个关键字参数可以不提供默认参数,但由于Python要求所有的形参必须绑定一个值,又由于关键字参数必须通过关键字指定,所以这个参数就变成了真正的“关键字参数”。

  1. 第二个语法变化是可以省略可变参数的变量名(只写一个星号),这表示函数可以指定“关键字参数”但不接收可变位置参数。
1
2
def compare(a, b, *, key=None):
    ...

做这个语法改变的原因是这样的,假如你想函数接收几个位置参数以及一个关键字参数,比如:

1
2
def compare(a, b, key=None):
    ...

为了让这个关键字参数变成真正的“关键字参数”,根据上面的语法,你可能会这样写:

1
2
def compare(a, b, *ignore, key=None):
    ...

但很遗憾,这样写并不对,因为这个可变的位置参数会吸收任何错误的关键字参数。为了在发生这种情况的时候抛出错误,我们可能会打个这样的补丁:

1
2
3
def compare(a, b, *ignore, key=None):
    if ignore:  # If ignore is not empty
        raise TypeError

作为一种简洁的写法,PEP3102提议允许省略 ignore 的变量名,意思是后面不接收任何位置参数,如提供则会报错。

补充

PEP3102 还详述了函数调用时,输入参数分配给形式参数的过程:

  1. 对每一个形式参数,都有一个槽位,用来保存分配给该参数的值。
  2. 已经分配的槽位标记为:“已填充”,尚未分配的槽位标记为:“空”。
  3. 刚开始的时候,所有的槽位都标记为“空”。
  4. 先分配位置参数,然后分配关键字参数。
  5. 对于每一个位置参数:尝试绑定到第一个未分配的槽位,如果这个槽位不是可变长槽位,则将这个槽位标记为:“已填充”。
  6. 分配位置参数时,如果下一个槽位是可变长槽位,并且没有变量名,则报错。
  7. 分配位置参数时,如果下一个槽位是可变长槽位,有变量名,则将剩余的所有非关键字参数全放到这个槽位中。
  8. 对于每一个关键字参数:如果有形参的变量名与之相同,则将该参数赋值给此形参。然而,如果该形参槽位已经被填充,则报错。
  9. 分配关键字参数时,如果有“关键字字典”形参,即可变长关键字参数槽位,则将该参数放到该字典中。然而,如果该字典中已经有该关键字,则报错。
  10. 分配关键字参数时,如果没有可变长关键字参数槽位,也没有同变量名的形参,则报错。
  11. 最后,如果可变长位置参数槽位没有被填充,则赋值空元组给它。
  12. 对于每一个剩余的没被填充的槽位,如果有默认值则赋值默认值给它,如果没有默认值,则报错。

原文如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Function Calling Behavior
The previous section describes the difference between the old behavior and the new. However, it is also useful to have a description of the new behavior that stands by itself, without reference to the previous model. So this next section will attempt to provide such a description.

When a function is called, the input arguments are assigned to formal parameters as follows:

For each formal parameter, there is a slot which will be used to contain the value of the argument assigned to that parameter.
Slots which have had values assigned to them are marked as ‘filled’. Slots which have no value assigned to them yet are considered ‘empty’.
Initially, all slots are marked as empty.
Positional arguments are assigned first, followed by keyword arguments.
For each positional argument:
Attempt to bind the argument to the first unfilled parameter slot. If the slot is not a vararg slot, then mark the slot as ‘filled’.
If the next unfilled slot is a vararg slot, and it does not have a name, then it is an error.
Otherwise, if the next unfilled slot is a vararg slot then all remaining non-keyword arguments are placed into the vararg slot.
For each keyword argument:
If there is a parameter with the same name as the keyword, then the argument value is assigned to that parameter slot. However, if the parameter slot is already filled, then that is an error.
Otherwise, if there is a ‘keyword dictionary’ argument, the argument is added to the dictionary using the keyword name as the dictionary key, unless there is already an entry with that key, in which case it is an error.
Otherwise, if there is no keyword dictionary, and no matching named parameter, then it is an error.
Finally:
If the vararg slot is not yet filled, assign an empty tuple as its value.
For each remaining empty slot: if there is a default value for that slot, then fill the slot with the default value. If there is no default value, then it is an error.

2. 斜杠 /

作用:表示斜杠前的参数必须通过位置传递(Positional-Only),不能使用关键字参数形式。

示例:

1
2
3
4
5
6
def func(a, b, /, c):
    print(a, b, c)

func(1, 2, 3)      # 正确:a、b是位置参数
func(1, 2, c=3)    # 正确:c可以是关键字参数
func(a=1, b=2, c=3)  # 错误:a、b不能是关键字参数

用途:通常用于确保某些参数必须按位置传递(例如,避免与可能的关键字参数名冲突)。

发展历史

详见 PEP570 文档(2019年):PEP 570 – Python Positional-Only Parameters

出现这个提案的原因之一:

  1. 一些代码库的作者并不希望一些api的参数可以通过关键字传递,因为在api初期,参数的名字可能语义化并不强,比如 arg1、arg2等,如果这时用户通过关键字调用了,后期想改api的函数签名就会出现问题。

3. 混合使用 * 和 /

可以同时使用两者来明确参数传递规则:

1
2
3
4
5
6
7
def func(a, /, b, *, c):
    print(a, b, c)

func(1, 2, c=3)    # 正确
func(1, b=2, c=3)  # 正确
func(a=1, b=2, c=3) # 错误:a不能是关键字参数
func(1, 2, 3)      # 错误:c必须是关键字参数

4. 总结

符号 含义 示例 支持版本
* 右侧参数必须按关键字传递(Keyword-Only) def f(a, *, b): Python 3.0+
/ 左侧参数必须按位置传递(Positional-Only) def f(a, /, b): Python 3.8+
updatedupdated2026-02-052026-02-05