什么是 *args 和 **kwargs?

293

*args**kwargs 究竟是什么意思?

根据Python文档,看起来它传递了一个参数元组。

def foo(hello, *args):
    print(hello)

    for each in args:
        print(each)

if __name__ == '__main__':
    foo("LOVE", ["lol", "lololol"])

这将打印出:

LOVE
['lol', 'lololol']

如何有效地使用它们?


20
对“小时”和“千瓦时”进行了一个无聊的双关语。 - Mostlyharmless
6
这篇文章可以非常有用地深入理解主题:http://agiliq.com/blog/2012/06/understanding-args-and-kwargs/。 - Badarau Petru
5个回答

281

*args和/或**kwargs放在函数定义的参数列表末尾,允许该函数接受任意数量的参数和/或关键字参数。

例如,如果您想编写一个函数,返回其所有参数的总和,无论您提供多少个参数,您可以像这样编写它:

def my_sum(*args):
    return sum(args)

在面向对象编程中,当你要覆盖一个函数并希望使用用户传递的任何参数调用原始函数时,***是非常常见的用法。实际上,你不必将它们命名为argskwargs,那只是一种约定俗成的写法。

Python官方文档提供了更深入的解释


6
没问题,非常感谢。我也曾有过困惑。如果你认真学习Python,我强烈推荐Mark Lutz的《Programming Python》。 - Paul D. Waite
46
或许可以链接到深入解释这个问题的教程,每个人都应该阅读:http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions - Ali Afshar
1
@AliAfshar:你的链接就是我需要的,本来应该就是答案。谢谢! - scorpiodawg
3
没问题。我想知道有多少新手尝试使用你的代码时发现了这个错误,但却告诉自己“我一定是在这里做错了,因为这个答案得到了那么多赞”;) 我会再给你点赞的,因为它很清晰,也很好。 - Tadeck
@Tadeck:我不敢想象。哦,谢谢你。 - Paul D. Waite
2
@scorpiodawg,只提供链接的答案不被看好,因为它们链接的网站可能会消失,使答案对未来的访问者无用。 - George Stocker

98

此外,我们也使用它们来管理继承。

class Super( object ):
   def __init__( self, this, that ):
       self.this = this
       self.that = that

class Sub( Super ):
   def __init__( self, myStuff, *args, **kw ):
       super( Sub, self ).__init__( *args, **kw )
       self.myStuff= myStuff

x= Super( 2.7, 3.1 )
y= Sub( "green", 7, 6 )

使用这种方式,子类并不真正知道(或关心)其超类的初始化。如果您意识到需要更改超类,则可以在不必为每个子类中的细节而感到焦虑的情况下解决问题。


6
这是我在如何使用super方面找到的最有帮助的答案之一。虽然这个答案已经超过5年了,但我猜在Python 2.X中仍然是使用super的一个很好的方法,是吗? - Amelio Vazquez-Reina
是的,仍然是这样做的方式。 - user75506
谢谢,但如果您能提供一些真实的例子,说明何时以及为什么要使用它,那就太好了。在上面的例子中,如果我不这样做会发生什么? - TaraGurung

75

注意在S.Lott的评论中提到的酷炫事情——您还可以使用*mylist**mydict来解包位置参数和关键字参数的函数调用:

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

l = [0, 1]
d = {"d":3, "c":2}

foo(*l, **d)

将打印:0 1 2 3


你实际上也可以使用 *mydict(而不是 **mylist),但结果会略有不同(对某些人来说可能出乎意料)。 - Tadeck
3
英译中。仅返回翻译文本:简单、简洁、易于理解的例子来说明观点。这是我最喜欢的回答方式! - NickO
1
@Tadeck,您可以对任何可迭代对象使用*x,对于任何映射类型,您可以使用**y。由于字典既是可迭代的又是映射的,因此您可以选择任意一种方式。请参见https://dev59.com/dmoy5IYBdhLWcg3wYM2B。 - augurar

26

使用*args**kwargs的另一个好处是,您可以定义通用的“捕获所有”函数,这对于返回此类包装器而不是原始函数的装饰器非常有用。

以下是一个带有简单缓存装饰器的示例:

import pickle, functools
def cache(f):
  _cache = {}
  def wrapper(*args, **kwargs):
    key = pickle.dumps((args, kwargs))
    if key not in _cache:
      _cache[key] = f(*args, **kwargs) # call the wrapped function, save in cache
    return _cache[key] # read value from cache
  functools.update_wrapper(wrapper, f) # update wrapper's metadata
  return wrapper

import time
@cache
def foo(n):
  time.sleep(2)
  return n*2

foo(10) # first call with parameter 10, sleeps
foo(10) # returns immediately

20

仅澄清如何解包参数,处理缺少的参数等。

def func(**keyword_args):
  #-->keyword_args is a dictionary
  print 'func:'
  print keyword_args
  if keyword_args.has_key('b'): print keyword_args['b']
  if keyword_args.has_key('c'): print keyword_args['c']

def func2(*positional_args):
  #-->positional_args is a tuple
  print 'func2:'
  print positional_args
  if len(positional_args) > 1:
    print positional_args[1]

def func3(*positional_args, **keyword_args):
  #It is an error to switch the order ie. def func3(**keyword_args, *positional_args):
  print 'func3:'
  print positional_args
  print keyword_args

func(a='apple',b='banana')
func(c='candle')
func2('apple','banana')#It is an error to do func2(a='apple',b='banana')
func3('apple','banana',a='apple',b='banana')
func3('apple',b='banana')#It is an error to do func3(b='banana','apple')

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