参数列表中的星号有什么作用?什么是“仅限关键字”参数?

问题描述 投票:0回答:5

函数参数中的星号有什么作用?

当我查看 pickle 模块时,我看到了这个:

pickle.dump(obj, file, protocol=None, *, fix_imports=True)

我知道参数前面有一个星号和两个星号(对于可变数量的参数),但是这没有先于任何内容。我很确定这与泡菜无关。这可能只是发生这种情况的一个例子。当我把它发送给翻译时我才知道它的名字:

>>> def func(*):
...     pass
...
  File "<stdin>", line 1
SyntaxError: named arguments must follow bare *

如果重要的话,我使用的是 python 3.3.0。

python python-3.x parameter-passing keyword-argument positional-argument
5个回答
437
投票

Bare

*
用于强制调用者使用命名参数 - 因此,当您没有以下关键字参数时,无法使用
*
作为参数定义函数。

请参阅此答案Python 3文档了解更多详细信息。


124
投票

虽然原始答案完全回答了问题,只是添加了一些相关信息。单个星号的行为源自

PEP-3102
。引用相关部分:

The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:

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

用简单的英语来说,这意味着要传递键的值,您需要将其显式传递为

key="value"


77
投票
def func(*, a, b):
    print(a)
    print(b)

func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb

上面的例子带有 **kwargs

def func(*, a, b, **kwargs):
    print(a)
    print(b)
    print(kwargs)

func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}

76
投票

从语义上讲,这意味着它后面的参数仅是关键字,因此如果您尝试提供参数而不指定其名称,您将收到错误。例如:

>>> def f(a, *, b):
...     return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3

实际上,这意味着您必须使用关键字参数来调用该函数。通常在没有论证名称给出的提示而很难理解论证的目的时这样做。

比较例如

sorted(nums, reverse=True)
与如果您写了
sorted(nums, True)
。后者的可读性要差得多,因此 Python 开发人员选择让您以前一种方式编写。


强制参数仅使用关键字(或仅使用位置,带有

/
)的另一个具体原因是确保
@lru_cache
的使用一致。像
@lru_cache
这样的装饰器将
f(1, 2)
f(1, b=2)
视为不同的调用,因此如果这两个调用在同一个程序中进行,您将无法获得缓存的全部好处。例如:

>>> from functools import lru_cache
>>> @lru_cache
... def f(a, b):
...     print(f'Non-cached call with {a=}, {b=}')
...     return a + b
... 
>>> f(1, 2)
Non-cached call with a=1, b=2
3
>>> f(1, 2) # cached result is used
3
>>> f(1, b=2) # cached result is not used
Non-cached call with a=1, b=2
3

因此,强制所有调用以相同的方式传递参数是有实际好处的。


32
投票

假设你有功能:

def sum(a,key=5):
    return a + key 

您可以通过两种方式调用此函数:

sum(1,2)
sum(1,key=2)

假设您希望仅使用关键字参数调用函数

sum

*
添加到函数参数列表中以标记位置参数的结尾。

所以函数定义为:

def sum(a,*,key=5):
    return a + key 

只能使用

sum(1,key=2)

来调用
© www.soinside.com 2019 - 2024. All rights reserved.