【问题标题】:Bare asterisk in function arguments?函数参数中的裸星号?
【发布时间】:2012-12-27 10:34:00
【问题描述】:

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

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

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


【解决方案1】:

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

请参阅this answerPython 3 documentation 了解更多详情。

【讨论】:

【解决方案2】:

虽然原始答案完全回答了问题,但只是添加了一些相关信息。单个星号的行为源自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"

【讨论】:

  • 哦,这让事情更清楚了。所以实际上有一个参数 * 就像有一个参数 args *,但由于你没有给它命名,它唯一的效果可能是悄悄地吞噬所有剩余的位置参数,以便强制剩余的参数成为关键字-仅。
  • @Stephen 我最初也认为,裸 * 的效果是吞噬剩余的位置参数,但事实并非如此。传递比函数预期更多的位置参数,会产生这种错误:foo() takes exactly 1 positional argument (2 given)
  • 我会在“作为一种方便的快捷方式,我们可以简单地省略'ignore'名称,意思是'不允许任何位置参数超出这一点'之前添加PEP示例。”这个等价的例子清楚而具体地说明了它的作用。
【解决方案3】:
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'}

【讨论】:

    【解决方案4】:

    我发现以下链接对解释 **args**kwargs 非常有帮助:

    https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/

    基本上,除了上面的答案之外,我还从上面的网站(信用:https://pythontips.com/author/yasoob008/)了解到以下内容:

    下面先定义演示函数,有两个例子,一个是*args,一个是**kwargs

    def test_args_kwargs(arg1, arg2, arg3):
        print "arg1:", arg1
        print "arg2:", arg2
        print "arg3:", arg3
    
    # first with *args
    >>> args = ("two", 3,5)
    >>> test_args_kwargs(*args)
    arg1: two
    arg2: 3
    arg3: 5
    
    # now with **kwargs:
    >>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
    >>> test_args_kwargs(**kwargs)
    arg1: 5
    arg2: two
    arg3: 3
    

    所以*args 允许您动态构建一个参数列表,这些参数将按照输入的顺序进行处理,而**kwargs 可以启用命名参数的传递,并且可以由 NAME 相应地处理(无论喂食顺序)。

    网站继续,并指出参数的正确顺序应该是:

    some_func(fargs,*args,**kwargs)
    

    【讨论】:

    • 这个答案几乎与问题无关。它甚至使用了没有该功能的过时 python 版本。
    【解决方案5】:

    假设你有函数:

    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)调用

    【讨论】:

      【解决方案6】:

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

      >>> 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 开发人员选择让你用前一种方式编写它。

      【讨论】:

        猜你喜欢
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-30
        • 2012-12-28
        相关资源
        最近更新 更多