使用*args和**kwargs

Mac*_*hon 1367 python args kwargs

所以我有这个概念的困难*args**kwargs.

到目前为止,我已经了解到:

  • *args =参数列表 - 作为位置参数
  • **kwargs = dictionary - 其键成为单独的关键字参数,值成为这些参数的值.

我不明白这会对哪些编程任务有所帮助.

也许:

我想输入列表和字典作为函数AND的参数同时作为通配符,所以我可以传递任何参数?

有一个简单的例子来说明如何*args**kwargs使用?

我发现的教程也使用了"*"和变量名.

*args**kwargs刚才占位符或者你使用完全相同*args,并**kwargs在代码中?

Dav*_*ebb 1631

语法是***.名称*args**kwargs仅按照惯例,但有使用它们没有硬性要求.

*args当你不确定可以向你的函数传递多少个参数时,你会使用它,即它允许你向函数传递任意数量的参数.例如:

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print( '{0}. {1}'.format(count, thing))
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage
Run Code Online (Sandbox Code Playgroud)

同样,**kwargs允许您处理事先未定义的命名参数:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print( '{0} = {1}'.format(name, value))
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit
Run Code Online (Sandbox Code Playgroud)

您也可以将这些与命名参数一起使用.显式参数首先获取值,然后将其他所有内容传递给*args**kwargs.命名参数在列表中排在第一位.例如:

def table_things(titlestring, **kwargs)
Run Code Online (Sandbox Code Playgroud)

您也可以在同一个函数定义中使用它们,但*args必须在之前使用**kwargs.

调用函数时也可以使用***语法.例如:

>>> def print_three_things(a, b, c):
...     print( 'a = {0}, b = {1}, c = {2}'.format(a,b,c))
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat
Run Code Online (Sandbox Code Playgroud)

正如您在本案中所看到的,它会获取项目的列表(或元组)并将其解包.通过这个它将它们与函数中的参数匹配.当然,您可以*在函数定义和函数调用中同时使用.

  • 你会在python的帮助/文档中看到这个怎么样? (13认同)
  • @Alex:[here](https://docs.python.org/2/tutorial/controlflow.html#arbitrary-argument-lists) (13认同)
  • @ mlh3789是的,这只适用于python3.但真正有点奇怪的是:这种方法适用于赋值:`a,b,*c,d,e = 1,2,3,4,5,6`将c分配给[3,4].有点混乱 (7认同)

Mar*_*ent 474

使用*args**kwargs非常有用的一个地方是子类化.

class Foo(object):
    def __init__(self, value1, value2):
        # do something with the values
        print value1, value2

class MyFoo(Foo):
    def __init__(self, *args, **kwargs):
        # do something else, don't care about the args
        print 'myfoo'
        super(MyFoo, self).__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这样你就可以扩展Foo类的行为,而不必过多地了解Foo.如果您正在编程可能会更改的API,这可能非常方便.MyFoo只是将所有参数传递给Foo类.

  • 如果您已经了解*和**,这个答案真的有意义. (114认同)
  • 我不明白.如果您的API发生了更改,您仍然需要更改实例化子类的所有位置.如果你要改变所有这些地方,那么你也可以修复子类的签名,而不是无缘无故地与args和kwargs一起攻击.你不需要了解Foo的原因是没有意义的,因为一旦Foo构造函数的set签名发生变化,你所有的MyFoo实例化调用都必须改变.这需要了解Foo及其构造函数所需的参数. (6认同)
  • @ZoranPavlovic可以使用此示例的示例是您要为现有产品提供附加组件并希望覆盖/扩展某些功能.通过使用*args和**kwargs,如果底层产品发生变化,这个附加组件将继续运行.但是,实例化MyFoo发生在加载项之外.这是否更有意义?(话虽如此:装饰器是一个更好的例子,可以使用*args和**kwargs.) (2认同)

Kit*_*Kit 308

这是一个使用3种不同类型参数的示例.

def func(required_arg, *args, **kwargs):
    # required_arg is a positional-only parameter.
    print required_arg

    # args is a tuple of positional arguments,
    # because the parameter name has * prepended.
    if args: # If args is not empty.
        print args

    # kwargs is a dictionary of keyword arguments,
    # because the parameter name has ** prepended.
    if kwargs: # If kwargs is not empty.
        print kwargs

>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes at least 1 argument (0 given)

>>> func("required argument")
required argument

>>> func("required argument", 1, 2, '3')
required argument
(1, 2, '3')

>>> func("required argument", 1, 2, '3', keyword1=4, keyword2="foo")
required argument
(1, 2, '3')
{'keyword2': 'foo', 'keyword1': 4}
Run Code Online (Sandbox Code Playgroud)


Way*_*ner 71

这是我最喜欢使用**语法的地方之一,如Dave Webb的最后一个例子:

mynum = 1000
mystr = 'Hello World!'
print "{mystr} New-style formatting is {mynum}x more fun!".format(**locals())
Run Code Online (Sandbox Code Playgroud)

与仅使用名称本身相比,我不确定它是否非常快,但输入起来要容易得多!

  • 嘿,这家伙发明了Python 3.6 f-strings之前很酷 (24认同)
  • @dabadaba祝贺成为今天的[幸运10k](https://xkcd.com/1053/) (3认同)

jch*_*chl 45

*args和**kwargs有用的一种情况是编写包装器函数(例如装饰器)时需要能够接受任意参数传递给被包装的函数.例如,一个简单的装饰器打印参数并返回被包装函数的值:

def mydecorator( f ):
   @functools.wraps( f )
   def wrapper( *args, **kwargs ):
      print "Calling f", args, kwargs
      v = f( *args, **kwargs )
      print "f returned", v
      return v
   return wrapper
Run Code Online (Sandbox Code Playgroud)


Ste*_*ohr 36

*args和**kwargs是Python的特殊魔法功能.想想一个可能有未知数量的参数的函数.例如,不管是什么原因,你想拥有的功能,总结未知数量的数字(和你不希望使用内置的SUM函数).所以你写这个函数:

def sumFunction(*args):
  result = 0
  for x in args:
    result += x
  return result
Run Code Online (Sandbox Code Playgroud)

并使用它:sumFunction(3,4,6,3,6,8,9).

**kwargs具有不同的功能.随着**kwargs,你可以给一个函数给任意关键字参数,你可以访问他们的dictonary.

def someFunction(**kwargs):
  if 'text' in kwargs:
    print kwargs['text']
Run Code Online (Sandbox Code Playgroud)

调用someFunction(text ="foo")将打印foo.


Fel*_*ing 18

想象一下你有一个功能,但你不想限制它所需的参数数量.例:

>>> import operator
>>> def multiply(*args):
...  return reduce(operator.mul, args)
Run Code Online (Sandbox Code Playgroud)

然后你使用这个函数,如:

>>> multiply(1,2,3)
6

or

>>> numbers = [1,2,3]
>>> multiply(*numbers)
6
Run Code Online (Sandbox Code Playgroud)


Joh*_*ooy 17

名称*args**kwargs**kw纯粹按惯例.它使我们更容易阅读彼此的代码

一个方便的地方是使用struct模块

struct.unpack()返回一个元组,而struct.pack()使用可变数量的参数.当操纵数据时,能够将元组传递给struck.pack()例如是方便的.

tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)
Run Code Online (Sandbox Code Playgroud)

如果没有这种能力,你将被迫写作

new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)
Run Code Online (Sandbox Code Playgroud)

这也意味着如果format_str改变并且元组的大小发生变化,我将不得不返回并编辑那个很长的行


yoy*_*oyo 9

请注意,*args/**kwargs是函数调用语法的一部分,而不是真正的运算符.这有一个特殊的副作用,我遇到了,你不能使用*args扩展与print语句,因为print不是一个函数.

这似乎是合理的:

def myprint(*args):
    print *args
Run Code Online (Sandbox Code Playgroud)

不幸的是它没有编译(语法错误).

这编译:

def myprint(*args):
    print args
Run Code Online (Sandbox Code Playgroud)

但是将参数打印为元组,这不是我们想要的.

这是我解决的解决方案:

def myprint(*args):
    for arg in args:
        print arg,
    print
Run Code Online (Sandbox Code Playgroud)

  • 当然总是`from __future__ import print_function` :) (8认同)
  • print是Python3中的一个函数:) http://docs.python.org/3.0/whatsnew/3.0.html (4认同)

Rud*_*udi 8

这些参数通常用于代理函数,因此代理可以将任何输入参数传递给目标函数.

def foo(bar=2, baz=5):
    print bar, baz

def proxy(x, *args, **kwargs): # reqire parameter x and accept any number of additional arguments
    print x
    foo(*args, **kwargs) # applies the "non-x" parameter to foo

proxy(23, 5, baz='foo') # calls foo with bar=5 and baz=foo
proxy(6)# calls foo with its default arguments
proxy(7, bar='asdas') # calls foo with bar='asdas' and leave baz default argument
Run Code Online (Sandbox Code Playgroud)

但由于这些参数隐藏了实际的参数名称,因此最好避免使用它们.