**(双星/星号)和*(星/星号)对参数有何作用?

发布于 2025-01-14 18:19:03 字数 282 浏览 3 评论 0原文

这些函数定义中的 *args**kwargs 意味着什么?

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

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

请参阅**(双星/星号)和*(星号/星号)在函数调用中意味着什么?关于论证的补充问题。

What do *args and **kwargs mean in these function definitions?

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

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

See What do ** (double star/asterisk) and * (star/asterisk) mean in a function call? for the complementary question about arguments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(28

*args**kwargs 是常见的习惯用法,允许函数使用任意数量的参数,如 Python 教程中有关定义函数的更多信息

*args 将为您提供所有位置参数 作为元组

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, bar=None, **kwargs):
    print(kind, args, bar, kwargs)

foo(123, 'a', 'b', apple='red')
# 123 ('a', 'b') None {'apple': 'red'}

也可以以相反的方式使用:

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)

baz = [1, 2]

foo(*baz)
# 1 2

在 Python 3 中,可以在赋值的左侧使用 *l (扩展可迭代解包),尽管它在此上下文中给出了一个列表而不是元组:

first, *rest = [1, 2, 3, 4]
# first = 1
# rest = [2, 3, 4]

Python 3 还添加了一个新的语义(请参阅 PEP 3102):

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

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

注意:

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

The *args and **kwargs are common idioms to allow an arbitrary number of arguments to functions, as described in the section more on defining functions in the Python tutorial.

The *args will give you all positional arguments as a tuple:

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1, 2, 3)
# 1
# 2
# 3

The **kwargs will give you all
keyword arguments as a dictionary:

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name='one', age=27)
# name one
# age 27

Both idioms can be mixed with normal arguments to allow a set of fixed and some variable arguments:

def foo(kind, *args, bar=None, **kwargs):
    print(kind, args, bar, kwargs)

foo(123, 'a', 'b', apple='red')
# 123 ('a', 'b') None {'apple': 'red'}

It is also possible to use this the other way around:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100, **obj)
# 100 10 lee

Another usage of the *l idiom is to unpack argument lists when calling a function.

def foo(bar, lee):
    print(bar, lee)

baz = [1, 2]

foo(*baz)
# 1 2

In Python 3 it is possible to use *l on the left side of an assignment (Extended Iterable Unpacking), though it gives a list instead of a tuple in this context:

first, *rest = [1, 2, 3, 4]
# first = 1
# rest = [2, 3, 4]

Also Python 3 adds a new semantic (refer PEP 3102):

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

Such function accepts only 3 positional arguments, and everything after * can only be passed as keyword arguments.

Note:

A Python dict, semantically used for keyword argument passing, is arbitrarily ordered. However, in Python 3.6+, keyword arguments are guaranteed to remember insertion order.
"The order of elements in **kwargs now corresponds to the order in which keyword arguments were passed to the function." - What’s New In Python 3.6.
In fact, all dicts in CPython 3.6 will remember insertion order as an implementation detail, and this becomes standard in Python 3.7.

紫竹語嫣☆ 2025-01-21 18:19:03

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

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'

It's also worth noting that you can use * and ** when calling functions as well. This is a shortcut that allows you to pass multiple arguments to a function directly using either a list/tuple or a dictionary. For example, if you have the following function:

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

You can do things like:

>>> 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

Note: The keys in mydict have to be named exactly like the parameters of function foo. Otherwise it will throw a 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'
维持三分热 2025-01-21 18:19:03

单个 * 意味着可以有任意数量的额外位置参数。 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}

The single * means that there can be any number of extra positional arguments. foo() can be invoked like foo(1,2,3,4,5). In the body of foo() param2 is a sequence containing 2-5.

The double ** means there can be any number of extra named parameters. bar() can be invoked like bar(1, a=2, b=3). In the body of bar() param2 is a dictionary containing {'a':2, 'b':3 }

With the following code:

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)

the output is

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}
甜扑 2025-01-21 18:19:03

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

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

定义函数

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

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

您可以(并且应该)选择任何适当的名称,但如果目的是使参数具有非特定语义,则 args 和 kwargs 是标准名称。

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

您还可以使用 *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 - 例如,这里,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 中使用 *** 表示法的常见习惯用法。这些特定的变量名称不是必需的(例如,您可以使用 *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) prints:

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 允许我们做,我们减少线路代码,提高可读性和可维护性,并为我们的程序中的逻辑提供唯一的规范位置。如果我们需要更改此结构的任何部分,我们都有一个地方可以进行每项更改。

What does ** (double star) and * (star) do for parameters?

They allow for functions to be defined to accept and for users to pass any number of arguments, positional (*) and keyword (**).

Defining Functions

*args allows for any number of optional positional arguments (parameters), which will be assigned to a tuple named args.

**kwargs allows for any number of optional keyword arguments (parameters), which will be in a dict named kwargs.

You can (and should) choose any appropriate name, but if the intention is for the arguments to be of non-specific semantics, args and kwargs are standard names.

Expansion, Passing any number of arguments

You can also use *args and **kwargs to pass in parameters from lists (or any iterable) and dicts (or any mapping), respectively.

The function recieving the parameters does not have to know that they are being expanded.

For example, Python 2's xrange does not explicitly expect *args, but since it takes 3 integers as arguments:

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

As another example, we can use dict expansion in str.format:

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

New in Python 3: Defining functions with keyword only arguments

You can have keyword only arguments after the *args - for example, here, kwarg2 must be given as a keyword argument - not positionally:

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

Usage:

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

Also, * can be used by itself to indicate that keyword only arguments follow, without allowing for unlimited positional arguments.

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

Here, kwarg2 again must be an explicitly named, keyword argument:

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

And we can no longer accept unlimited positional arguments because we don't have *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

Again, more simply, here we require kwarg to be given by name, not positionally:

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

In this example, we see that if we try to pass kwarg positionally, we get an error:

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

We must explicitly pass the kwarg parameter as a keyword argument.

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

Python 2 compatible demos

*args (typically said "star-args") and **kwargs (stars can be implied by saying "kwargs", but be explicit with "double-star kwargs") are common idioms of Python for using the * and ** notation. These specific variable names aren't required (e.g. you could use *foos and **bars), but a departure from convention is likely to enrage your fellow Python coders.

We typically use these when we don't know what our function is going to receive or how many arguments we may be passing, and sometimes even when naming every variable separately would get very messy and redundant (but this is a case where usually explicit is better than implicit).

Example 1

The following function describes how they can be used, and demonstrates behavior. Note the named b argument will be consumed by the second positional argument before :

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

We can check the online help for the function's signature, with help(foo), which tells us

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

Let's call this function with foo(1, 2, 3, 4, e=5, f=6, g=7)

which prints:

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}

Example 2

We can also call it using another function, into which we just provide 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) prints:

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}

Example 3: practical usage in decorators

OK, so maybe we're not seeing the utility yet. So imagine you have several functions with redundant code before and/or after the differentiating code. The following named functions are just pseudo-code for illustrative purposes.

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

We might be able to handle this differently, but we can certainly extract the redundancy with a decorator, and so our below example demonstrates how *args and **kwargs can be very useful:

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

And now every wrapped function can be written much more succinctly, as we've factored out the redundancy:

@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)

And by factoring out our code, which *args and **kwargs allows us to do, we reduce lines of code, improve readability and maintainability, and have sole canonical locations for the logic in our program. If we need to change any part of this structure, we have one place in which to make each change.

南烟 2025-01-21 18:19:03

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

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

在函数定义中,“*”运算符将接收到的参数打包到一个元组中。

现在让我们看一个在函数定义中使用“**”的示例:

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

在函数定义中,“**”运算符将接收到的参数打包到字典中。

因此请记住:

函数调用中,“*”将元组或列表的数据结构解压为位置参数或关键字参数,以由函数定义接收。

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

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

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

Let us first understand what are positional arguments and keyword arguments.
Below is an example of function definition with Positional arguments.

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

So this is a function definition with positional arguments.
You can call it with keyword/named arguments as well:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

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

Now let us study an example of function definition with keyword arguments:

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
-------------------------

You can call this function with positional arguments as well:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

So we now know function definitions with positional as well as keyword arguments.

Now let us study the '*' operator and '**' operator.

Please note these operators can be used in 2 areas:

a) function call

b) function definition

The use of '*' operator and '**' operator in function call.

Let us get straight to an example and then discuss it.

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.

So remember

when the '*' or '**' operator is used in a function call -

'*' operator unpacks data structure such as a list or tuple into arguments needed by function definition.

'**' operator unpacks a dictionary into arguments needed by function definition.

Now let us study the '*' operator use in function definition.
Example:

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

In function definition the '*' operator packs the received arguments into a tuple.

Now let us see an example of '**' used in function 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

In function definition The '**' operator packs the received arguments into a dictionary.

So remember:

In a function call the '*' unpacks data structure of tuple or list into positional or keyword arguments to be received by function definition.

In a function call the '**' unpacks data structure of dictionary into positional or keyword arguments to be received by function definition.

In a function definition the '*' packs positional arguments into a tuple.

In a function definition the '**' packs keyword arguments into a dictionary.

夜还是长夜 2025-01-21 18:19:03

该表可以方便地在函数构造和函数调用中使用***

            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 的答案,但我发现它很有帮助。

相关地:star/splat 运算符的使用已 在 Python 3 中扩展了

This table is handy for using * and ** in function construction and function call:

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

This really just serves to summarize Lorin Hochstein's answer but I find it helpful.

Relatedly: uses for the star/splat operators have been expanded in Python 3

執念 2025-01-21 18:19:03

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',年龄=33)
  3. 接受任何使用 *args, **kwargs 的位置和关键字参数数量: def foo(*args, **kwargs): pass,此处为 foo 接受任意数量的位置和关键字参数,即以下调用有效 foo(1,name='Tom'), foo(1, 'bar', name ='汤姆',年龄=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 是仅位置,而 c 或 d 可以是位置或关键字,e 或 f 必须是关键字:

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

BONUS 2这个答案对同一个问题也带来了一个新的视角,它分享了*的内容** 表示在函数调用函数签名for 循环等中。

TL;DR

Below are 6 different use cases for * and ** in python programming:

  1. To accept any number of positional arguments using *args: def foo(*args): pass, here foo accepts any number of positional arguments, i. e., the following calls are valid foo(1), foo(1, 'bar')
  2. To accept any number of keyword arguments using **kwargs: def foo(**kwargs): pass, here 'foo' accepts any number of keyword arguments, i. e., the following calls are valid foo(name='Tom'), foo(name='Tom', age=33)
  3. To accept any number of positional and keyword arguments using *args, **kwargs: def foo(*args, **kwargs): pass, here foo accepts any number of positional and keyword arguments, i. e., the following calls are valid foo(1,name='Tom'), foo(1, 'bar', name='Tom', age=33)
  4. To enforce keyword only arguments using *: def foo(pos1, pos2, *, kwarg1): pass, here * means that foo only accept keyword arguments after pos2, hence foo(1, 2, 3) raises TypeError but foo(1, 2, kwarg1=3) is ok.
  5. To express no further interest in more positional arguments using *_ (Note: this is a convention only): def foo(bar, baz, *_): pass means (by convention) foo only uses bar and baz arguments in its working and will ignore others.
  6. To express no further interest in more keyword arguments using **_ (Note: this is a convention only): def foo(bar, baz, **_): pass means (by convention) foo only uses bar and baz arguments in its working and will ignore others.

BONUS: From python 3.8 onward, one can use / in function definition to enforce positional only parameters. In the following example, parameters a and b are positional-only, while c or d can be positional or keyword, and e or f are required to be keywords:

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

BONUS 2: THIS ANSWER to the same question also brings a new perspective, where it shares what does * and ** means in a function call, functions signature, for loops, etc.

很酷不放纵 2025-01-21 18:19:03

*** 在函数参数列表中具有特殊用途。 <代码>*
暗示参数是一个列表,而 ** 暗示参数
是一本字典。这允许函数采用任意数量的
论点

* and ** have special usage in the function argument list. *
implies that the argument is a list and ** implies that the argument
is a dictionary. This allows functions to take arbitrary number of
arguments

落叶缤纷 2025-01-21 18:19:03

对于那些通过例子学习的人!

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

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

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. 如果适用,** 必须始终位于 * 之后。

For those of you who learn by examples!

  1. The purpose of * is to give you the ability to define a function that can take an arbitrary number of arguments provided as a list (e.g. f(*myList) ).
  2. The purpose of ** is to give you the ability to feed a function's arguments by providing a dictionary (e.g. f(**{'x' : 1, 'y' : 2}) ).

Let us show this by defining a function that takes two normal variables x, y, and can accept more arguments as myArgs, and can accept even more arguments as myKW. Later, we will show how to feed y using myArgDict.

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   = {}
# ----------------------------------------------------------------------

Caveats

  1. ** is exclusively reserved for dictionaries.
  2. Non-optional argument assignment happens first.
  3. You cannot use a non-optional argument twice.
  4. If applicable, ** must come after *, always.
魄砕の薆 2025-01-21 18:19:03

来自 Python 文档:

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

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

From the Python documentation:

If there are more positional arguments than there are formal parameter slots, a TypeError exception is raised, unless a formal parameter using the syntax "*identifier" is present; in this case, that formal parameter receives a tuple containing the excess positional arguments (or an empty tuple if there were no excess positional arguments).

If any keyword argument does not correspond to a formal parameter name, a TypeError exception is raised, unless a formal parameter using the syntax "**identifier" is present; in this case, that formal parameter receives a dictionary containing the excess keyword arguments (using the keywords as keys and the argument values as corresponding values), or a (new) empty dictionary if there were no excess keyword arguments.

窝囊感情。 2025-01-21 18:19:03

* 表示接收变量参数作为元组

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

使用如下:

1) single *

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

* means receive variable arguments as tuple

** means receive variable arguments as dictionary

Used like the following:

1) single *

def foo(*args):
    for arg in args:
        print(arg)

foo("two", 3)

Output:

two
3

2) Now **

def bar(**kwargs):
    for key in kwargs:
        print(key, kwargs[key])

bar(dic1="two", dic2=3)

Output:

dic1 two
dic2 3
笔芯 2025-01-21 18:19:03

在 Python 3.5 中,您还可以在 listdicttupleset 显示中使用此语法(也可以有时称为文字)。请参阅PEP 488:其他解包概括

>>> (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 链接。)

In Python 3.5, you can also use this syntax in list, dict, tuple, and set displays (also sometimes called literals). See 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}

It also allows multiple iterables to be unpacked in a single function call.

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

(Thanks to mgilson for the PEP link.)

不忘初心 2025-01-21 18:19:03

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- keywords", "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)

TL;DR

It packs arguments passed to the function into list and dict respectively inside the function body. When you define a function signature like this:

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

it can be called with any number of arguments and keyword arguments. The non-keyword arguments get packed into a list called args inside the function body and the keyword arguments get packed into a dict called kwds inside the function body.

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

now inside the function body, when the function is called, there are two local variables, args which is a list having value ["this", "is a list of", "non-keyword", "arguments"] and kwds which is a dict having value {"keyword" : "ligma", "options" : [1,2,3]}


This also works in reverse, i.e. from the caller side. for example if you have a function defined as:

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

you can call it with by unpacking iterables or mappings you have in the calling scope:

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)
坚持沉默 2025-01-21 18:19:03

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

* 还可以解压一个生成器

来自Python3文档的例子

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x will be (1, 2, 3), unzip_y will be (4, 5, 6 )

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

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

I want to give an example which others haven't mentioned

* can also unpack a generator

An example from Python3 Document

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x will be (1, 2, 3), unzip_y will be (4, 5, 6)

The zip() receives multiple iretable args, and return a generator.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))
阿楠 2025-01-21 18:19:03

基于 nickd 的答案...

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。

Building on nickd's 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)

Output:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

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

Basically, any number of positional arguments can use *args and any named arguments (or kwargs aka keyword arguments) can use **kwargs.

木落 2025-01-21 18:19:03

除了函数调用之外,*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')

完整代码为 这里

In addition to function calls, *args and **kwargs are useful in class hierarchies and also avoid having to write __init__ method in Python. Similar usage can seen in frameworks like Django code.

For example,

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

A subclass can then be

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

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

The subclass then be instantiated as

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

Also, a subclass with a new attribute which makes sense only to that subclass instance can call the Base class __init__ to offload the attributes setting.
This is done through *args and **kwargs. kwargs mainly used so that code is readable using named arguments. For example,

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)

which can be instatiated as

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

The complete code is here

冷了相思 2025-01-21 18:19:03

给定一个有 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 * 运算符执行此解包过程。

输入图像描述这里

Given a function that has 3 items as argument

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

Imagine this toy with a bag of a triangle, a circle and a rectangle item. That bag does not directly fit. You need to unpack the bag to take those 3 items and now they fit. The Python * operator does this unpack process.

enter image description here

国产ˉ祖宗 2025-01-21 18:19:03

函数定义中的星号“*”将多个位置参数组合为一个元组参数。

>>> 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

The asterisk '*' in a function definition combines multiple positional arguments into a single tuple argument.

>>> def A(*tpl):
...     print(tpl)
...
>>> A(6, 7, 8, 9, 0)
(6, 7, 8, 9, 0)

The asterisk '*' in a function call splits a sequence into individual positional arguments.

>>> 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 

The double asterisk '**' in a function definition combines multiple keyword arguments into a single dictionary argument.

>>> 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}

The double asterisk '**' in a function call splits a dictionary-like object into individual keyword arguments.

>>> 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
阳光①夏 2025-01-21 18:19:03

*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.

*args and **kwargs: allow you to pass a variable number of arguments to a function.

*args: is used to send a non-keyworded variable length argument list to the function:

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')

Will produce:

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 allows you to pass keyworded variable length of arguments to a function. You should use **kwargs if you want to handle named arguments in a function.

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")  

Will produce:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
云醉月微眠 2025-01-21 18:19:03

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

>>> 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')
{}

A good example of using both in a function is:

>>> 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')
{}
牛↙奶布丁 2025-01-21 18:19:03

这个示例将帮助您立即记住 Python 中的 *args**kwargs 甚至 super 和继承。

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

This example would help you remember *args, **kwargs and even super and inheritance in Python at once.

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
握住你手 2025-01-21 18:19:03

*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 或 **任何
这是一个字典类型

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

def func(**any):
    return any

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


*args ( or *any ) means every parameters

def any_param(*param):
    pass

any_param(1)
any_param(1,1)
any_param(1,1,1)
any_param(1,...)

NOTICE : you can don't pass parameters to *args

def any_param(*param):
    pass

any_param() # will work correct

The *args is in type tuple

def any_param(*param):
    return type(param)

any_param(1) #tuple
any_param() # tuple

for access to elements don't use of *

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

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

The **kwd

**kwd or **any
This is a dict type

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

def func(**any):
    return any

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


远山浅 2025-01-21 18:19:03
  • *args 是特殊参数,可以将 0 个或多个(位置)参数作为元组。

  • **kwargs 是特殊参数,可以将 0 个或多个(关键字)参数作为字典。

*在Python中,有2种参数位置参数和关键字参数

*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

And, args 具有 tuple 类型:

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

输出:

<class 'tuple'>

But, * 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 不能放在 < code>*args 如下所示:

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

输出(错误):

语法错误:语法无效

并且,普通参数不能放在 *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 has dict类型:

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)

Output(错误):

语法错误:语法无效

对于 *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}
  • *args is the special parameter which can take 0 or more (positional) arguments as a tuple.

  • **kwargs is the special parameter which can take 0 or more (keyword) arguments as a dictionary.

*In Python, there are 2 kinds of arguments positional argument and keyword argument:

*args:

For example, *args can take 0 or more arguments as a tuple as shown below:

           ↓
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

Output:

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

And, when printing *args, 4 numbers are printed without parentheses and commas:

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

Output:

1 2 3 4

And, args has tuple type:

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

Output:

<class 'tuple'>

But, *args has no type:

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

Output(Error):

TypeError: type() takes 1 or 3 arguments

And, normal parameters can be put before *args as shown below:

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

Output:

1 2 (3, 4)

But, **kwargs cannot be put before *args as shown below:

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

Output(Error):

SyntaxError: invalid syntax

And, normal parameters cannot be put after *args as shown below:

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

Output(Error):

TypeError: test() missing 2 required keyword-only arguments: 'num1' and 'num2'

But, if normal parameters have default values, they can be put after *args as shown below:

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

Output:

(1, 2) 3 4

And also, **kwargs can be put after *args as shown below:

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

Output:

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

**kwargs:

For example, **kwargs can take 0 or more arguments as a dictionary as shown below:

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

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

Output:

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

And, when printing *kwargs, 2 keys are printed:

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

Output:

name age

And, kwargs has dict type:

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

Output:

<class 'dict'>

But, *kwargs and **kwargs have no type:

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

Output(Error):

TypeError: type() takes 1 or 3 arguments

And, normal parameters can be put before **kwargs as shown below:

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

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

Output:

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

And also, *args can be put before **kwargs as shown below:

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

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

Output:

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

And, normal parameters and *args cannot be put after **kwargs as shown below:

                    ↓     ↓
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)

Output(Error):

SyntaxError: invalid syntax

For both *args and **kwargs:

Actually, you can use other names for *args and **kwargs as shown below. *args and **kwargs are used conventionally:

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

Output:

(1, 2) {'num1': 3, 'num2': 4}
望喜 2025-01-21 18:19:03

上下文

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

使用字符串格式

除了本线程中的答案之外,这里还有其他地方未提及的另一个细节。这扩展了 Brad Solomon 的回答

使用 ** 解包在使用 python 时也很有用 <代码>str.format。

这有点类似于 python f-strings f-string但声明一个字典来保存变量会增加开销(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])

Context

  • python 3.x
  • unpacking with **
  • use with string formatting

Use with string formatting

In addition to the answers in this thread, here is another detail that was not mentioned elsewhere. This expands on the answer by Brad Solomon

Unpacking with ** is also useful when using python str.format.

This is somewhat similar to what you can do with python f-strings f-string but with the added overhead of declaring a dict to hold the variables (f-string does not require a dict).

Quick Example

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

带刺的爱情 2025-01-21 18:19:03

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

The most simple explanation is just that * is *args, which passes a tuple, and ** is **kwargs, which passes a dictionary. Those are just general names that are default.

姐不稀罕 2025-01-21 18:19:03

两者都是 *args & **kwargs 允许我们将多个参数传递给 python 方法,但有一些差异如下所述:

*args

用于按顺序传递 n 个参数就像数组一样,每个元素都会跟随并索引。

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

据我所知, *args 是一个用逗号 , 分隔的参数数组,所以如果你想在上面的 foo ,它看起来像

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

因此,如果您运行

for a in args:
        print(a)  

它,它将按放置顺序打印参数:1,2,3...

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


**kwargs

在这里被称为关键字参数,您也可以传递可变数量的参数,但参数很像字典 k/v 对。

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

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

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

并可以在函数中单独读取它,如下所示

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

读取 kwargs 不需要枚举循环,并且参数的顺序并不重要。

Both *args & **kwargs allows us to pass multiple arguments/parameters to a python method but there are few differences explained below:

*args

Is used to pass n-numbers of arguments in order much like a Array every element will follow and index.

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

As far as I know, *args is an array of arguments separated by comma , so if you wanted to to foo above it will look like

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

so if you run

for a in args:
        print(a)  

it will print arguments in order of placement as 1,2,3...

Although this is very easy to implement and use the order of arguments matters a lot here. So if the first argument is supposed to be a string and second and integer, if the caller messed with the order the function fails.


**kwargs

These are called keyword arguments here also you can pass variable numbers of arguments but the arguments are much like a dictionary k/v pair.

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

These are keyword arguments which are set of named arguments which are passed as key/value pair or dictionary separated by , if multiple. So for bar you can send

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

and can read it in the function individually as

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

Reading kwargs doesn't required to enumerate over a loop and order of arguments don't matter.

寄离 2025-01-21 18:19:03
  • def foo(param1, *param2): 是一个可以接受任意数量的 *param2 值的方法,
  • def bar(param1, **param2):< /code> 是一个可以接受任意数量的值的方法,其键为 *param2
  • param1 是一个简单参数。

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

accessModifier methodName(datatype… arg) {
    // method body
}
  • def foo(param1, *param2): is a method can accept arbitrary number of values for *param2,
  • def bar(param1, **param2): is a method can accept arbitrary number of values with keys for *param2
  • param1 is a simple parameter.

For example, the syntax for implementing varargs in Java as follows:

accessModifier methodName(datatype… arg) {
    // method body
}
梦毁影碎の 2025-01-21 18:19:03

带有 *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')
!
"""

"Infinite" Args with *args and **kwargs

*args and **kwargs are just some way to input unlimited characters to functions, like:


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')
!
"""
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文