【问题标题】:**(双星/星号)和*(星号/星号)对参数有什么作用?
【发布时间】:2026-02-19 15:15:01
【问题描述】:

在下面的方法定义中,***param2 做了什么?

def foo(param1, *param2):
def bar(param1, **param2):

【问题讨论】:

  • 这个问题是一个非常流行的重复目标,但不幸的是它经常被错误地使用。请记住,这个问题询问的是使用可变参数定义函数 (def func(*args))。有关询问函数 calls (func(*[1,2])) 中的含义的问题,请参阅 here。有关如何解压缩参数列表的问题,请参阅here。对于询问*literals ([*[1, 2]]) 中的含义的问题,请参阅here
  • @Aran-Fey:我认为“函数调用中的含义”的更好目标是What does the star operator mean, in a function call?Your link 并没有真正解决 ** 的使用问题,它是一个更狭窄的问题。

标签: python syntax parameter-passing variadic-functions argument-unpacking


【解决方案1】:

来自 Python 文档:

如果位置参数的数量多于形参槽的数量,则会引发 TypeError 异常,除非存在使用语法“*identifier”的形参;在这种情况下,该形式参数接收一个包含多余位置参数的元组(如果没有多余的位置参数,则接收一个空元组)。

如果任何关键字参数不对应形式参数名称,则会引发 TypeError 异常,除非存在使用语法“**identifier”的形式参数;在这种情况下,该形式参数接收一个包含多余关键字参数的字典(使用关键字作为键,参数值作为对应值),或者如果没有多余的关键字参数,则接收一个(新)空字典。

【讨论】:

    【解决方案2】:

    *args**kwargs 是一个常见的习惯用法,允许函数使用任意数量的参数,如 Python 文档中的 more on defining functions 部分所述。

    *args 会给你所有的函数参数as a tuple:

    def foo(*args):
        for a in args:
            print(a)        
    
    foo(1)
    # 1
    
    foo(1,2,3)
    # 1
    # 2
    # 3
    

    **kwargs 会给你所有 关键字参数除了作为字典的形式参数对应的那些。

    def bar(**kwargs):
        for a in kwargs:
            print(a, kwargs[a])  
    
    bar(name='one', age=27)
    # name one
    # age 27
    

    这两个习语都可以与普通参数混合,以允许一组固定和一些可变参数:

    def foo(kind, *args, **kwargs):
       pass
    

    也可以反过来使用:

    def foo(a, b, c):
        print(a, b, c)
    
    obj = {'b':10, 'c':'lee'}
    
    foo(100,**obj)
    # 100 10 lee
    

    *l 习惯用法的另一种用法是在调用函数时解压缩参数列表

    def foo(bar, lee):
        print(bar, lee)
    
    l = [1,2]
    
    foo(*l)
    # 1 2
    

    在 Python 3 中,可以在赋值 (Extended Iterable Unpacking) 的左侧使用 *l,尽管在这种情况下它给出的是列表而不是元组:

    first, *rest = [1,2,3,4]
    first, *l, last = [1,2,3,4]
    

    Python 3 也增加了新的语义(参考PEP 3102):

    def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
        pass
    

    此类函数仅接受 3 个位置参数,* 之后的所有内容都只能作为关键字参数传递。

    注意:

    • Python dict,语义上用于关键字参数传递,是任意排序的。但是,在 Python 3.6 中,保证关键字参数会记住插入顺序。
    • **kwargs 中元素的顺序现在对应于传递给函数的关键字参数的顺序。” - What’s New In Python 3.6
    • 事实上,CPython 3.6 中的所有字典都会记住插入顺序作为实现细节,这在 Python 3.7 中成为标准。

    【讨论】:

      【解决方案3】:

      单个 * 表示可以有任意数量的额外位置参数。 foo() 可以像 foo(1,2,3,4,5) 一样调用。在 foo() 的主体中 param2 是一个包含 2-5 的序列。

      双 ** 表示可以有任意数量的额外命名参数。 bar() 可以像 bar(1, a=2, b=3) 一样调用。在 bar() param2 的主体中是一个包含 {'a':2, 'b':3 }

      的字典

      使用以下代码:

      def foo(param1, *param2):
          print(param1)
          print(param2)
      
      def bar(param1, **param2):
          print(param1)
          print(param2)
      
      foo(1,2,3,4,5)
      bar(1,a=2,b=3)
      

      输出是

      1
      (2, 3, 4, 5)
      1
      {'a': 2, 'b': 3}
      

      【讨论】:

        【解决方案4】:

        另外值得注意的是,您也可以在调用函数时使用***。这是一个快捷方式,允许您使用列表/元组或字典直接将多个参数传递给函数。例如,如果您有以下功能:

        def foo(x,y,z):
            print("x=" + str(x))
            print("y=" + str(y))
            print("z=" + str(z))
        

        您可以执行以下操作:

        >>> mylist = [1,2,3]
        >>> foo(*mylist)
        x=1
        y=2
        z=3
        
        >>> mydict = {'x':1,'y':2,'z':3}
        >>> foo(**mydict)
        x=1
        y=2
        z=3
        
        >>> mytuple = (1, 2, 3)
        >>> foo(*mytuple)
        x=1
        y=2
        z=3
        

        注意:mydict 中的键名必须与函数foo 的参数完全相同。否则会抛出TypeError:

        >>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
        >>> foo(**mydict)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        TypeError: foo() got an unexpected keyword argument 'badnews'
        

        【讨论】:

          【解决方案5】:

          *** 在函数参数列表中有特殊用法。 * 暗示参数是一个列表,** 暗示参数 是一本字典。这允许函数采用任意数量的 论据

          【讨论】:

            【解决方案6】:

            **(双星)和*(星)对参数有什么作用?

            它们允许定义函数以接受,并允许用户传递任意数量的参数、位置 (*) 和关键字 (**)。

            定义函数

            *args 允许任意数量的可选位置参数(参数),这些参数将分配给名为 args 的元组。

            **kwargs 允许任意数量的可选关键字参数(参数),它们将位于名为 kwargs 的字典中。

            您可以(并且应该)选择任何合适的名称,但如果意图使参数具有非特定语义,argskwargs 是标准名称。

            扩展,传递任意数量的参数

            您还可以使用*args**kwargs 分别从列表(或任何可迭代)和字典(或任何映射)传入参数。

            接收参数的函数不必知道它们正在被扩展。

            例如,Python 2 的 xrange 没有明确地期望 *args,但因为它需要 3 个整数作为参数:

            >>> x = xrange(3) # create our *args - an iterable of 3 integers
            >>> xrange(*x)    # expand here
            xrange(0, 2, 2)
            

            再举一个例子,我们可以在str.format中使用dict扩展:

            >>> foo = 'FOO'
            >>> bar = 'BAR'
            >>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
            'this is foo, FOO and bar, BAR'
            

            Python 3 中的新功能:使用仅关键字参数定义函数

            您可以在*args 之后添加keyword only arguments - 例如,此处kwarg2 必须作为关键字参数给出 - 而不是位置:

            def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
                return arg, kwarg, args, kwarg2, kwargs
            

            用法:

            >>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
            (1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})
            

            另外,* 可以单独使用,表示后面只有关键字参数,不允许无限的位置参数。

            def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
                return arg, kwarg, kwarg2, kwargs
            

            这里,kwarg2 必须是明确命名的关键字参数:

            >>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
            (1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})
            

            我们不能再接受无限的位置参数,因为我们没有*args*

            >>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
            Traceback (most recent call last):
              File "<stdin>", line 1, in <module>
            TypeError: foo() takes from 1 to 2 positional arguments 
                but 5 positional arguments (and 1 keyword-only argument) were given
            

            再一次,更简单地说,这里我们要求kwarg 按名称给出,而不是按位置给出:

            def bar(*, kwarg=None): 
                return kwarg
            

            在这个例子中,我们看到如果我们尝试在位置上传递kwarg,我们会得到一个错误:

            >>> bar('kwarg')
            Traceback (most recent call last):
              File "<stdin>", line 1, in <module>
            TypeError: bar() takes 0 positional arguments but 1 was given
            

            我们必须将kwarg 参数作为关键字参数显式传递。

            >>> bar(kwarg='kwarg')
            'kwarg'
            

            Python 2 兼容演示

            *args(通常表示“star-args”)和**kwargs(可以通过说“kwargs”来暗示星号,但用“double-star kwargs”明确表示)是 Python 使用 @ 的常见习语987654356@ 和 ** 表示法。这些特定的变量名不是必需的(例如,您可以使用 *foos**bars),但违反约定可能会激怒您的 Python 编码人员。

            当我们不知道我们的函数将接收什么或我们可能传递多少参数时,我们通常会使用这些,有时即使单独命名每个变量也会变得非常混乱和冗余(但这是一种情况通常显式优于隐式)。

            示例 1

            以下函数描述了它们的使用方法,并演示了行为。请注意,命名为 b 的参数将被之前的第二个位置参数使用:

            def foo(a, b=10, *args, **kwargs):
                '''
                this function takes required argument a, not required keyword argument b
                and any number of unknown positional arguments and keyword arguments after
                '''
                print('a is a required argument, and its value is {0}'.format(a))
                print('b not required, its default value is 10, actual value: {0}'.format(b))
                # we can inspect the unknown arguments we were passed:
                #  - args:
                print('args is of type {0} and length {1}'.format(type(args), len(args)))
                for arg in args:
                    print('unknown arg: {0}'.format(arg))
                #  - kwargs:
                print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                                    len(kwargs)))
                for kw, arg in kwargs.items():
                    print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
                # But we don't have to know anything about them 
                # to pass them to other functions.
                print('Args or kwargs can be passed without knowing what they are.')
                # max can take two or more positional args: max(a, b, c...)
                print('e.g. max(a, b, *args) \n{0}'.format(
                  max(a, b, *args))) 
                kweg = 'dict({0})'.format( # named args same as unknown kwargs
                  ', '.join('{k}={v}'.format(k=k, v=v) 
                                         for k, v in sorted(kwargs.items())))
                print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
                  dict(**kwargs), kweg=kweg))
            

            我们可以查看函数签名的在线帮助,help(foo)告诉我们

            foo(a, b=10, *args, **kwargs)
            

            让我们用foo(1, 2, 3, 4, e=5, f=6, g=7)调用这个函数

            哪个打印:

            a is a required argument, and its value is 1
            b not required, its default value is 10, actual value: 2
            args is of type <type 'tuple'> and length 2
            unknown arg: 3
            unknown arg: 4
            kwargs is of type <type 'dict'> and length 3
            unknown kwarg - kw: e, arg: 5
            unknown kwarg - kw: g, arg: 7
            unknown kwarg - kw: f, arg: 6
            Args or kwargs can be passed without knowing what they are.
            e.g. max(a, b, *args) 
            4
            e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
            {'e': 5, 'g': 7, 'f': 6}
            

            示例 2

            我们也可以使用另一个函数来调用它,我们只需提供a

            def bar(a):
                b, c, d, e, f = 2, 3, 4, 5, 6
                # dumping every local variable into foo as a keyword argument 
                # by expanding the locals dict:
                foo(**locals()) 
            

            bar(100) 打印:

            a is a required argument, and its value is 100
            b not required, its default value is 10, actual value: 2
            args is of type <type 'tuple'> and length 0
            kwargs is of type <type 'dict'> and length 4
            unknown kwarg - kw: c, arg: 3
            unknown kwarg - kw: e, arg: 5
            unknown kwarg - kw: d, arg: 4
            unknown kwarg - kw: f, arg: 6
            Args or kwargs can be passed without knowing what they are.
            e.g. max(a, b, *args) 
            100
            e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
            {'c': 3, 'e': 5, 'd': 4, 'f': 6}
            

            示例 3:装饰器中的实际用法

            好的,所以也许我们还没有看到该实用程序。因此,假设您在微分代码之前和/或之后有几个带有冗余代码的函数。以下命名函数只是用于说明目的的伪代码。

            def foo(a, b, c, d=0, e=100):
                # imagine this is much more code than a simple function call
                preprocess() 
                differentiating_process_foo(a,b,c,d,e)
                # imagine this is much more code than a simple function call
                postprocess()
            
            def bar(a, b, c=None, d=0, e=100, f=None):
                preprocess()
                differentiating_process_bar(a,b,c,d,e,f)
                postprocess()
            
            def baz(a, b, c, d, e, f):
                ... and so on
            

            我们或许能够以不同的方式处理这个问题,但我们当然可以使用装饰器提取冗余,因此我们下面的示例演示了 *args**kwargs 如何非常有用:

            def decorator(function):
                '''function to wrap other functions with a pre- and postprocess'''
                @functools.wraps(function) # applies module, name, and docstring to wrapper
                def wrapper(*args, **kwargs):
                    # again, imagine this is complicated, but we only write it once!
                    preprocess()
                    function(*args, **kwargs)
                    postprocess()
                return wrapper
            

            现在每个包装函数都可以更简洁地编写,因为我们已经排除了冗余:

            @decorator
            def foo(a, b, c, d=0, e=100):
                differentiating_process_foo(a,b,c,d,e)
            
            @decorator
            def bar(a, b, c=None, d=0, e=100, f=None):
                differentiating_process_bar(a,b,c,d,e,f)
            
            @decorator
            def baz(a, b, c=None, d=0, e=100, f=None, g=None):
                differentiating_process_baz(a,b,c,d,e,f, g)
            
            @decorator
            def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
                differentiating_process_quux(a,b,c,d,e,f,g,h)
            

            通过分解出我们的代码(*args**kwargs 允许我们这样做),我们减少了代码行数,提高了可读性和可维护性,并为我们的程序中的逻辑提供了唯一的规范位置。如果我们需要更改此结构的任何部分,我们可以在一个地方进行每次更改。

            【讨论】:

              【解决方案7】:

              除了函数调用之外,*args 和 **kwargs 在类层次结构中也很有用,并且还避免了在 Python 中编写 __init__ 方法。在 Django 代码等框架中可以看到类似的用法。

              例如,

              def __init__(self, *args, **kwargs):
                  for attribute_name, value in zip(self._expected_attributes, args):
                      setattr(self, attribute_name, value)
                      if kwargs.has_key(attribute_name):
                          kwargs.pop(attribute_name)
              
                  for attribute_name in kwargs.viewkeys():
                      setattr(self, attribute_name, kwargs[attribute_name])
              

              然后可以是子类

              class RetailItem(Item):
                  _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']
              
              class FoodItem(RetailItem):
                  _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']
              

              然后子类被实例化为

              food_item = FoodItem(name = 'Jam', 
                                   price = 12.0, 
                                   category = 'Foods', 
                                   country_of_origin = 'US', 
                                   expiry_date = datetime.datetime.now())
              

              此外,具有仅对该子类实例有意义的新属性的子类可以调用基类__init__ 来卸载属性设置。 这是通过 *args 和 **kwargs 完成的。 kwargs 主要用于使代码可以使用命名参数读取。例如,

              class ElectronicAccessories(RetailItem):
                  _expected_attributes = RetailItem._expected_attributes +  ['specifications']
                  # Depend on args and kwargs to populate the data as needed.
                  def __init__(self, specifications = None, *args, **kwargs):
                      self.specifications = specifications  # Rest of attributes will make sense to parent class.
                      super(ElectronicAccessories, self).__init__(*args, **kwargs)
              

              可以实例化为

              usb_key = ElectronicAccessories(name = 'Sandisk', 
                                              price = '$6.00', 
                                              category = 'Electronics',
                                              country_of_origin = 'CN',
                                              specifications = '4GB USB 2.0/USB 3.0')
              

              完整代码为here

              【讨论】:

                【解决方案8】:

                在 Python 3.5 中,您还可以在 listdicttupleset 显示(有时也称为文字)中使用此语法。见PEP 488: Additional Unpacking Generalizations

                >>> (0, *range(1, 4), 5, *range(6, 8))
                (0, 1, 2, 3, 5, 6, 7)
                >>> [0, *range(1, 4), 5, *range(6, 8)]
                [0, 1, 2, 3, 5, 6, 7]
                >>> {0, *range(1, 4), 5, *range(6, 8)}
                {0, 1, 2, 3, 5, 6, 7}
                >>> d = {'one': 1, 'two': 2, 'three': 3}
                >>> e = {'six': 6, 'seven': 7}
                >>> {'zero': 0, **d, 'five': 5, **e}
                {'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}
                

                它还允许在单个函数调用中解压缩多个迭代。

                >>> range(*[1, 10], *[2])
                range(1, 10, 2)
                

                (感谢 mgilson 提供 PEP 链接。)

                【讨论】:

                • 我不确定这是否违反了“只有一种方法可以做到”。没有其他方法可以从多个可迭代对象中初始化列表/元组——您目前需要将它们链接到单个可迭代对象中,这并不总是很方便。您可以在PEP-0448 中阅读有关理性的信息。此外,这不是 python3.x 功能,它是 python3.5+ 功能:-)。
                【解决方案9】:

                让我们首先了解什么是位置参数和关键字参数。 下面是一个带有位置参数的函数定义示例。

                def test(a,b,c):
                     print(a)
                     print(b)
                     print(c)
                
                test(1,2,3)
                #output:
                1
                2
                3
                

                所以这是一个带有位置参数的函数定义。 您也可以使用关键字/命名参数调用它:

                def test(a,b,c):
                     print(a)
                     print(b)
                     print(c)
                
                test(a=1,b=2,c=3)
                #output:
                1
                2
                3
                

                现在让我们研究一个带有关键字参数的函数定义示例:

                def test(a=0,b=0,c=0):
                     print(a)
                     print(b)
                     print(c)
                     print('-------------------------')
                
                test(a=1,b=2,c=3)
                #output :
                1
                2
                3
                -------------------------
                

                您也可以使用位置参数调用此函数:

                def test(a=0,b=0,c=0):
                    print(a)
                    print(b)
                    print(c)
                    print('-------------------------')
                
                test(1,2,3)
                # output :
                1
                2
                3
                ---------------------------------
                

                所以我们现在知道了带有位置参数和关键字参数的函数定义。

                现在让我们研究一下'*'运算符和'**'运算符。

                请注意,这些运算符可用于 2 个领域:

                a) 函数调用

                b) 函数定义

                函数调用中'*'操作符和'**'操作符的使用。

                让我们直接看一个例子,然后讨论它。

                def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
                    print(a+b)
                
                my_tuple = (1,2)
                my_list = [1,2]
                my_dict = {'a':1,'b':2}
                
                # Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
                sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
                sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
                sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 
                
                # output is 3 in all three calls to sum function.
                

                记住

                当在函数调用中使用'*'或'**'操作符时 -

                '*' 操作符将列表或元组等数据结构解包为函数定义所需的参数。

                '**' 操作符将字典解包成函数定义所需的参数。

                现在让我们研究一下函数定义中'*'操作符的使用。 示例:

                def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
                    sum = 0
                    for a in args:
                        sum+=a
                    print(sum)
                
                sum(1,2,3,4)  #positional args sent to function sum
                #output:
                10
                

                definition函数中,'*'操作符将接收到的参数打包成一个元组。

                现在让我们看一个在函数定义中使用'**'的例子:

                def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
                    sum=0
                    for k,v in args.items():
                        sum+=v
                    print(sum)
                
                sum(a=1,b=2,c=3,d=4) #positional args sent to function sum
                

                在函数定义中,'**'操作符将接收到的参数打包到字典中。

                所以记住:

                函数调用中,'*'解包元组或列表的数据结构为函数定义接收的位置或关键字参数。

                函数调用中,'**'解包字典的数据结构为函数定义接收的位置或关键字参数。

                函数定义中,'*'位置参数打包到一个元组中。

                函数定义中,'**'关键字参数打包到字典中。

                【讨论】:

                  【解决方案10】:

                  在函数中同时使用两者的一个很好的例子是:

                  >>> def foo(*arg,**kwargs):
                  ...     print arg
                  ...     print kwargs
                  >>>
                  >>> a = (1, 2, 3)
                  >>> b = {'aa': 11, 'bb': 22}
                  >>>
                  >>>
                  >>> foo(*a,**b)
                  (1, 2, 3)
                  {'aa': 11, 'bb': 22}
                  >>>
                  >>>
                  >>> foo(a,**b) 
                  ((1, 2, 3),)
                  {'aa': 11, 'bb': 22}
                  >>>
                  >>>
                  >>> foo(a,b) 
                  ((1, 2, 3), {'aa': 11, 'bb': 22})
                  {}
                  >>>
                  >>>
                  >>> foo(a,*b)
                  ((1, 2, 3), 'aa', 'bb')
                  {}
                  

                  【讨论】:

                    【解决方案11】:

                    我想举一个别人没有提到的例子

                    * 也可以解压一个generator

                    Python3 文档中的示例

                    x = [1, 2, 3]
                    y = [4, 5, 6]
                    
                    unzip_x, unzip_y = zip(*zip(x, y))
                    

                    unzip_x 将是 [1, 2, 3],unzip_y 将是 [4, 5, 6]

                    zip() 接收多个 iretable args,并返回一个生成器。

                    zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))
                    

                    【讨论】:

                    • unzip_x 将是 (1, 2, 3) 而不是 [1, 2, 3]。 unzip_y 也是如此
                    【解决方案12】:

                    此示例将帮助您同时记住*args**kwargs 甚至super 以及 Python 中的继承。

                    class base(object):
                        def __init__(self, base_param):
                            self.base_param = base_param
                    
                    
                    class child1(base): # inherited from base class
                        def __init__(self, child_param, *args) # *args for non-keyword args
                            self.child_param = child_param
                            super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg
                    
                    class child2(base):
                        def __init__(self, child_param, **kwargs):
                            self.child_param = child_param
                            super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg
                    
                    c1 = child1(1,0)
                    c2 = child2(1,base_param=0)
                    print c1.base_param # 0
                    print c1.child_param # 1
                    print c2.base_param # 0
                    print c2.child_param # 1
                    

                    【讨论】:

                      【解决方案13】:

                      此表便于在函数构造和函数调用中使用***

                                  In function construction         In function call
                      =======================================================================
                                |  def f(*args):                 |  def f(a, b):
                      *args     |      for arg in args:          |      return a + b
                                |          print(arg)            |  args = (1, 2)
                                |  f(1, 2)                       |  f(*args)
                      ----------|--------------------------------|---------------------------
                                |  def f(a, b):                  |  def f(a, b):
                      **kwargs  |      return a + b              |      return a + b
                                |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
                                |      return f(**kwargs)        |  f(**kwargs)
                                |  g(a=1, b=2)                   |
                      -----------------------------------------------------------------------
                      

                      这实际上只是对 Lorin Hochstein 的 answer 的总结,但我觉得它很有帮助。

                      相关:star/splat 运算符在 Python 3 中的用途是 expanded

                      【讨论】:

                      • 显然“splat”是星号 * 的行话。 catb.org/jargon/html/S/splat.html “星号 (*) 字符 (ASCII 0101010) 在许多地方(DEC、IBM 等)使用的名称。这可能源于许多早期行式打印机上星号的‘压扁错误’外观。”
                      【解决方案14】:

                      *args**kwargs:允许您将可变数量的参数传递给函数。

                      *args: 用于向函数发送非关键字变长参数列表:

                      def args(normal_arg, *argv):
                          print("normal argument:", normal_arg)
                      
                          for arg in argv:
                              print("Argument in list of arguments from *argv:", arg)
                      
                      args('animals', 'fish', 'duck', 'bird')
                      

                      将产生:

                      normal argument: animals
                      Argument in list of arguments from *argv: fish
                      Argument in list of arguments from *argv: duck
                      Argument in list of arguments from *argv: bird
                      

                      **kwargs*

                      **kwargs 允许您将关键字可变长度的参数传递给函数。如果你想在函数中处理命名参数,你应该使用**kwargs

                      def who(**kwargs):
                          if kwargs is not None:
                              for key, value in kwargs.items():
                                  print("Your %s is %s." % (key, value))
                      
                      who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")  
                      

                      将产生:

                      Your name is Nikola.
                      Your last_name is Tesla.
                      Your birthday is 7.10.1856.
                      Your birthplace is Croatia.
                      

                      【讨论】:

                        【解决方案15】:

                        献给那些通过例子学习的人!

                        1. * 的目的是让您能够定义一个函数,该函数可以接受以列表形式提供的任意数量的参数(例如 f(*myList))。
                        2. ** 的目的是让您能够通过提供字典(例如 f(**{'x' : 1, 'y' : 2}))来提供函数的参数。

                        让我们通过定义一个函数来展示这一点,该函数接受两个普通变量xy,并且可以接受更多参数为myArgs,并且可以接受更多参数为myKW。稍后,我们将展示如何使用myArgDicty

                        def f(x, y, *myArgs, **myKW):
                            print("# x      = {}".format(x))
                            print("# y      = {}".format(y))
                            print("# myArgs = {}".format(myArgs))
                            print("# myKW   = {}".format(myKW))
                            print("# ----------------------------------------------------------------------")
                        
                        # Define a list for demonstration purposes
                        myList    = ["Left", "Right", "Up", "Down"]
                        # Define a dictionary for demonstration purposes
                        myDict    = {"Wubba": "lubba", "Dub": "dub"}
                        # Define a dictionary to feed y
                        myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}
                        
                        # The 1st elem of myList feeds y
                        f("myEx", *myList, **myDict)
                        # x      = myEx
                        # y      = Left
                        # myArgs = ('Right', 'Up', 'Down')
                        # myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
                        # ----------------------------------------------------------------------
                        
                        # y is matched and fed first
                        # The rest of myArgDict becomes additional arguments feeding myKW
                        f("myEx", **myArgDict)
                        # x      = myEx
                        # y      = Why?
                        # myArgs = ()
                        # myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
                        # ----------------------------------------------------------------------
                        
                        # The rest of myArgDict becomes additional arguments feeding myArgs
                        f("myEx", *myArgDict)
                        # x      = myEx
                        # y      = y
                        # myArgs = ('y0', 'q')
                        # myKW   = {}
                        # ----------------------------------------------------------------------
                        
                        # Feed extra arguments manually and append even more from my list
                        f("myEx", 4, 42, 420, *myList, *myDict, **myDict)
                        # x      = myEx
                        # y      = 4
                        # myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')
                        # myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
                        # ----------------------------------------------------------------------
                        
                        # Without the stars, the entire provided list and dict become x, and y:
                        f(myList, myDict)
                        # x      = ['Left', 'Right', 'Up', 'Down']
                        # y      = {'Wubba': 'lubba', 'Dub': 'dub'}
                        # myArgs = ()
                        # myKW   = {}
                        # ----------------------------------------------------------------------
                        

                        注意事项

                        1. ** 专供字典使用。
                        2. 首先发生非可选参数赋值。
                        3. 您不能两次使用非可选参数。
                        4. 如果适用,** 必须始终位于 * 之后。

                        【讨论】:

                          【解决方案16】:

                          * 表示以元组形式接收变量参数

                          ** 表示接收变量参数作为字典

                          使用如下:

                          1) 单人 *

                          def foo(*args):
                              for arg in args:
                                  print(arg)
                          
                          foo("two", 3)
                          

                          输出:

                          two
                          3
                          

                          2) 现在**

                          def bar(**kwargs):
                              for key in kwargs:
                                  print(key, kwargs[key])
                          
                          bar(dic1="two", dic2=3)
                          

                          输出:

                          dic1 two
                          dic2 3
                          

                          【讨论】:

                            【解决方案17】:
                            • def foo(param1, *param2): 是一种可以为*param2 接受任意数量值的方法,
                            • def bar(param1, **param2): 是一种可以接受任意数量的值的方法,带有 *param2 的键
                            • param1 是一个简单的参数。

                            例如,在Java中实现varargs的语法如下:

                            accessModifier methodName(datatype… arg) {
                                // method body
                            }
                            

                            【讨论】:

                              【解决方案18】:

                              TL;DR

                              它将传递给函数的参数分别打包到函数体内的listdict中。当您像这样定义函数签名时:

                              def func(*args, **kwds):
                                  # do stuff
                              

                              可以使用任意数量的参数和关键字参数来调用它。非关键字参数被打包到函数体内名为 args 的列表中,关键字参数被打包到函数体内名为 kwds 的字典中。

                              func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])
                              

                              现在在函数体内,当函数被调用时,有两个局部变量,args 是一个列表,其值为 ["this", "is a list of", "non-keyword", "arguments"]kwds,这是一个 dict,其值为 {"keyword" : "ligma", "options" : [1,2,3]}


                              这也适用于反向,即从调用方。例如,如果您有一个函数定义为:

                              def f(a, b, c, d=1, e=10):
                                  # do stuff
                              

                              您可以通过解压缩调用范围内的可迭代对象或映射来调用它:

                              iterable = [1, 20, 500]
                              mapping = {"d" : 100, "e": 3}
                              f(*iterable, **mapping)
                              # That call is equivalent to
                              f(1, 20, 500, d=100, e=3)
                              

                              【讨论】:

                                【解决方案19】:

                                基于 nickd 的 answer...

                                def foo(param1, *param2):
                                    print(param1)
                                    print(param2)
                                
                                
                                def bar(param1, **param2):
                                    print(param1)
                                    print(param2)
                                
                                
                                def three_params(param1, *param2, **param3):
                                    print(param1)
                                    print(param2)
                                    print(param3)
                                
                                
                                foo(1, 2, 3, 4, 5)
                                print("\n")
                                bar(1, a=2, b=3)
                                print("\n")
                                three_params(1, 2, 3, 4, s=5)
                                

                                输出:

                                1
                                (2, 3, 4, 5)
                                
                                1
                                {'a': 2, 'b': 3}
                                
                                1
                                (2, 3, 4)
                                {'s': 5}
                                

                                基本上,任意数量的位置参数都可以使用 *args,任何命名参数(或 kwargs 又名关键字参数)都可以使用 **kwargs。

                                【讨论】:

                                  【解决方案20】:

                                  上下文

                                  • python 3.x
                                  • **解包
                                  • 与字符串格式一起使用

                                  与字符串格式一起使用

                                  除了这个帖子中的答案之外,还有其他地方没有提到的另一个细节。这扩展了answer by Brad Solomon

                                  在使用 python str.format 时,使用 ** 解包也很有用。

                                  这有点类似于您可以使用 python f-strings f-string 执行的操作,但增加了声明 dict 来保存变量的开销(f-string 不需要 dict)。

                                  快速示例

                                    ## init vars
                                    ddvars = dict()
                                    ddcalc = dict()
                                    pass
                                    ddvars['fname']     = 'Huomer'
                                    ddvars['lname']     = 'Huimpson'
                                    ddvars['motto']     = 'I love donuts!'
                                    ddvars['age']       = 33
                                    pass
                                    ddcalc['ydiff']     = 5
                                    ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
                                    pass
                                    vdemo = []
                                  
                                    ## ********************
                                    ## single unpack supported in py 2.7
                                    vdemo.append('''
                                    Hello {fname} {lname}!
                                  
                                    Today you are {age} years old!
                                  
                                    We love your motto "{motto}" and we agree with you!
                                    '''.format(**ddvars)) 
                                    pass
                                  
                                    ## ********************
                                    ## multiple unpack supported in py 3.x
                                    vdemo.append('''
                                    Hello {fname} {lname}!
                                  
                                    In {ydiff} years you will be {ycalc} years old!
                                    '''.format(**ddvars,**ddcalc)) 
                                    pass
                                  
                                    ## ********************
                                    print(vdemo[-1])
                                  
                                  

                                  【讨论】:

                                    【解决方案21】:

                                    TL;DR

                                    以下是python编程中***的6个不同用例:

                                    1. 要使用*args 接受任意数量的位置参数: def foo(*args): pass,这里foo 接受任意数量的位置参数,即。例如,以下调用有效foo(1)foo(1, 'bar')
                                    2. 要使用**kwargs 接受任意数量的关键字参数: def foo(**kwargs): pass,这里 'foo' 接受任意数量的关键字参数,即。例如,以下调用有效foo(name='Tom')foo(name='Tom', age=33)
                                    3. 要使用*args, **kwargs 接受任意数量的位置和关键字参数: def foo(*args, **kwargs): pass,这里foo 接受任意数量的位置和关键字参数,即。例如,以下调用有效foo(1,name='Tom')foo(1, 'bar', name='Tom', age=33)
                                    4. 使用* 强制只使用关键字参数: def foo(pos1, pos2, *, kwarg1): pass,这里* 表示 foo 只接受 pos2 之后的关键字参数,因此foo(1, 2, 3) 引发 TypeError 但foo(1, 2, kwarg1=3) 可以。李>
                                    5. 使用*_ 表示对更多位置参数不再感兴趣(注意:这只是一个约定): def foo(bar, baz, *_): pass 表示(按照约定)foo 仅使用barbaz工作中的争论,并会忽略其他人。
                                    6. 使用\**_ 表示对更多关键字参数不再感兴趣(注意:这只是一个约定): def foo(bar, baz, **_): pass 表示(按照约定)foo 仅使用barbaz工作中的争论,并会忽略其他人。

                                    奖励:从 python 3.8 开始,可以在函数定义中使用/ 来强制执行仅位置参数。在以下示例中,参数 a 和 b 是positional-only,而 c 或 d 可以是位置或关键字,而 e 或 f 必须是关键字:

                                    def f(a, b, /, c, d, *, e, f):
                                        pass
                                    

                                    【讨论】:

                                    • 使用/ 的一个原因是它允许您更改函数中的参数名称,而不必在调用函数的任何地方更新(您可以确定没有函数的调用者使用参数的名称来提供参数,因为它没有被使用)。
                                    【解决方案22】:

                                    给定一个有 3 个项目作为参数的函数

                                    sum = lambda x, y, z: x + y + z
                                    sum(1,2,3) # sum 3 items
                                    
                                    sum([1,2,3]) # error, needs 3 items, not 1 list
                                    
                                    x = [1,2,3][0]
                                    y = [1,2,3][1]
                                    z = [1,2,3][2]
                                    sum(x,y,z) # ok
                                    
                                    sum(*[1,2,3]) # ok, 1 list becomes 3 items
                                    

                                    想象一下这个玩具有一袋三角形、一个圆形和一个矩形物品。那个包不直接适合。您需要打开袋子才能拿走这 3 件物品,现在它们都装好了。 Python * 运算符执行此解包过程。

                                    【讨论】:

                                      【解决方案23】:

                                      *args ( or *any ) 表示每个参数

                                      def any_param(*param):
                                          pass
                                      
                                      any_param(1)
                                      any_param(1,1)
                                      any_param(1,1,1)
                                      any_param(1,...)
                                      

                                      注意:您不能将参数传递给 *args

                                      def any_param(*param):
                                          pass
                                      
                                      any_param() # will work correct
                                      

                                      *args 是元组类型

                                      def any_param(*param):
                                          return type(param)
                                      
                                      any_param(1) #tuple
                                      any_param() # tuple
                                      

                                      为了访问元素,不要使用 *

                                      def any(*param):
                                          param[0] # correct
                                      
                                      def any(*param):
                                          *param[0] # incorrect
                                      

                                      **kwd

                                      **kwd 或 **any 这是一个dict类型

                                      def func(**any):
                                          return type(any) # dict
                                      
                                      def func(**any):
                                          return any
                                      
                                      func(width="10",height="20") # {width="10",height="20")
                                      
                                      
                                      

                                      【讨论】: