双星号(**)和星号(*)在参数中的作用是什么?

3351

14
请参考以下链接:https://dev59.com/0mw05IYBdhLWcg3w41sp - Russia Must Remove Putin
159
这个问题是一个非常受欢迎的重复目标,但不幸的是,它经常被错误地使用。请记住,这个问题询问如何使用可变参数定义函数(def func(*args))。如果你想要了解在函数调用func(*[1,2]) 表示什么,请参见 这里。如果你想了解如何展开参数列表,请参见 这里。如果你想了解在 字面量 中 ([*[1, 2]]) * 的含义,请参见 这里 - Aran-Fey
4
我认为"What does it mean in function calls"的更好翻译应该是"在函数调用中星号操作符的含义是什么?",而不是你提供的链接"https://dev59.com/wG435IYBdhLWcg3wvyw5"。这个链接并没有真正回答`**`的使用,而且它的问题范围更窄。 - ShadowRanger
1
这个问题 - 像许多非常古老的问题一样 - 有点反向; 通常一个问题应该是关于如何解决新代码中的问题,而不是如何理解现有代码。对于后者,如果您要将其他内容视为重复项,请考虑 https://dev59.com/VnI-5IYBdhLWcg3wKE6x(尽管这仅涵盖 * 而不是 **)。 - Karl Knechtel
我在https://youtu.be/sYeqpnAA7U4中使用星号运算符解释了解包。 - Dr Nisha Arora
显示剩余2条评论
28个回答

2

*args(或*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是一个字典类型

def func(**any):
    return type(any) # dict

def func(**any):
    return any

func(width="10",height="20") # {width="10",height="20")



2

背景

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

与字符串格式化一起使用

除了本主题中的答案外,还有一个细节没有在其他地方提到。这扩展了Brad Solomon的答案

使用**进行解包时,在使用Python str.format时也非常有用。

这与您可以使用Python f-strings做的事情有些类似,但需要声明一个字典来保存变量(f-string不需要字典)。

快速示例

  ## 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])


1
  • *args 是一种特殊的参数,可以作为元组接受0个或多个位置参数。

  • **kwargs 是一种特殊的参数,可以作为字典接受0个或多个关键字参数。

*在Python中,有两种类型的参数:位置参数和关键字参数

*args:

例如,*args 可以将0个或多个参数作为元组接受,如下所示:

def test(*args):
    print(args)

test() # Here
test(1, 2, 3, 4) # Here
test((1, 2, 3, 4)) # Here
test(*(1, 2, 3, 4)) # Here

输出:

()
(1, 2, 3, 4)
((1, 2, 3, 4),)
(1, 2, 3, 4)

当打印*args时,会打印4个数字,没有括号和逗号:

def test(*args):
    print(*args) # Here
 
test(1, 2, 3, 4)

输出:

1 2 3 4

而且,args 的类型是元组

def test(*args):
    print(type(args)) # Here
 
test(1, 2, 3, 4)

输出:

<class 'tuple'>

然而,*args 没有类型:

def test(*args):
    print(type(*args)) # Here
 
test(1, 2, 3, 4)

输出(错误):

类型错误:type()需要1个或3个参数

而且,正常的参数可以放在*args之前,如下所示:

          ↓     ↓
def test(num1, num2, *args):
    print(num1, num2, args)
    
test(1, 2, 3, 4)

输出:

1 2 (3, 4)

但是,如下所示,**kwargs不能放在*args之前:
def test(**kwargs, *args):
    print(kwargs, args)
    
test(num1=1, num2=2, 3, 4)

输出(错误):

SyntaxError:无效语法

而且,正常参数不能像下面这样放在*args之后:

                 ↓     ↓
def test(*args, num1, num2):
    print(args, num1, num2)
    
test(1, 2, 3, 4)

输出(错误):

类型错误: test()缺少2个必要的关键字参数: 'num1'和'num2'

但是,如果普通参数有默认值,它们可以放在*args之后,如下所示:

                      ↓         ↓
def test(*args, num1=100, num2=None):
    print(args, num1, num2)
    
test(1, 2, num1=3, num2=4)

输出:

(1, 2) 3 4

此外,**kwargs 也可以放在 *args 后面,如下所示:

def test(*args, **kwargs):
    print(args, kwargs)
    
test(1, 2, num1=3, num2=4)

输出:

(1, 2) {'num1': 3, 'num2': 4}

**kwargs

例如,**kwargs可以作为一个字典来接收0个或多个参数,如下所示:

def test(**kwargs):
    print(kwargs)

test() # Here
test(name="John", age=27) # Here
test(**{"name": "John", "age": 27}) # Here

输出:

{}
{'name': 'John', 'age': 27}
{'name': 'John', 'age': 27}

当打印*kwargs时,会打印2个键:

def test(**kwargs):
    print(*kwargs) # Here
 
test(name="John", age=27)

输出:

name age

而且,kwargs字典 类型:

def test(**kwargs):
    print(type(kwargs)) # Here
 
test(name="John", age=27)

输出:

<class 'dict'>

然而,*kwargs**kwargs 是没有类型的:

def test(**kwargs):
    print(type(*kwargs)) # Here
 
test(name="John", age=27)

def test(**kwargs):
    print(type(**kwargs)) # Here
 
test(name="John", age=27)

输出(错误):

类型错误: type()只接受1个或3个参数

而且,普通参数可以放在 **kwargs 前面,如下所示:

          ↓     ↓
def test(num1, num2, **kwargs):
    print(num1, num2, kwargs)

test(1, 2, name="John", age=27)

输出:

1 2 {'name': 'John', 'age': 27}

此外,*args也可以放在**kwargs之前,如下所示:

def test(*args, **kwargs):
    print(args, kwargs)

test(1, 2, name="John", age=27)

输出:

(1, 2) {'name': 'John', 'age': 27}

普通参数和*args不能放在**kwargs之后,如下所示:

                    ↓     ↓
def test(**kwargs, num1, num2):
    print(kwargs, num1, num2)

test(name="John", age=27, 1, 2)

def test(**kwargs, *args):
    print(kwargs, args)

test(name="John", age=27, 1, 2)

输出(错误):

SyntaxError: 语法无效

对于 *args**kwargs

实际上,你可以使用其他名称来代替 *args**kwargs,如下所示。 *args**kwargs 是传统用法:

            ↓        ↓
def test(*banana, **orange):
    print(banana, orange)
    
test(1, 2, num1=3, num2=4)

输出:

(1, 2) {'num1': 3, 'num2': 4}

1
def foo(x, y, *args):
    pass

def bar(x, y, **kwargs):
    pass

*args

据我所知,*args 是由逗号 , 分隔的参数数组,因此如果您想要在上面使用 foo,它将如下所示:

foo("x","y",1,2,3,4,5)

所以如果你运行

for a in args:
        print(a)  

它将按放置顺序打印参数为1、2、3...

虽然这很容易实现和使用,但参数的顺序在这里非常重要。因此,如果第一个参数应该是字符串,第二个参数是整数,如果调用者弄错了顺序,函数就会失败。


**kwargs

这些是关键字参数,它们是一组以键/值对字典形式传递的命名参数,如果有多个,则用,分隔。因此,对于bar,您可以发送

bar("x", "y", name="vinod",address="bangalore",country="india")

并且可以在函数中单独读取它

Name = kwargs['name']
Address = kwargs['address'] 


阅读 kwargs 不需要枚举循环,参数的顺序也不重要。

1
在函数定义中,星号“*”将多个位置参数组合成一个单一的元组参数。
>>> def A(*tpl):
...     print(tpl)
...
>>> A(6, 7, 8, 9, 0)
(6, 7, 8, 9, 0)

在函数调用中,星号'*'将一个序列拆分为单独的位置参数。
>>> def B(a, b, c, d, e):
...     print(f"{a} {b} {c} {d} {e}")
...
>>> lst = [1,2,3,4,5]
>>>
>>> B(*lst)
1 2 3 4 5 

在函数定义中,双星号 '**' 将多个关键字参数合并为一个字典参数。
>>> def C(**dic):
...     print(dic)
...
>>> C(a=9, b=8, c=7, d=6, e=5)
{'a': 9, 'b': 8, 'c': 7, 'd': 6, 'e': 5}

在函数调用中,双星号 '**' 将一个类似于字典的对象拆分为单独的关键字参数。
>>> def D(v,w,x,y,z):
...     print(f"{v} {w} {x} {y} {z}")
...
>>> dct = {'z':1, 'y':2, 'x':3, 'w':4, 'v':5}
>>>
>>> D(**dct)
5 4 3 2 1

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

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

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

0

"无限"参数与*args和**kwargs

*args**kwargs只是一种将无限数量的字符输入函数的方法,例如:


def print_all(*args, **kwargs):
    print(args) # print any number of arguments like: "print_all("foo", "bar")"
    print(kwargs.get("to_print")) # print the value of the keyworded argument "to_print"


# example:
print_all("Hello", "World", to_print="!")
# will print:
"""
('Hello', 'World')
!
"""

*args can be anything, like *something, the same for **kwargs, example: *keyworded_args - Isaac Vinícius

0
最简单的解释就是 * 是 *args,它传递一个元组,而 ** 是 **kwargs,它传递一个字典。这些只是默认的通用名称。

这个问题已经有25个答案了,为什么要添加一个重复其他答案的新答案呢? - bfontaine
所有之前的答案都更加复杂,只需要简化它即可... - happymancer

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