关于python:*args”和**kwargs是什么意思?

What do *args and **kwargs mean?

本问题已经有最佳答案,请猛点这里访问。

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

根据python文档,从表面上看,它传递一组参数。

1
2
3
4
5
6
7
8
def foo(hello, *args):
    print hello

    for each in args:
        print each

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

打印出:

1
2
LOVE
['lol', 'lololol']

你如何有效地使用它们?


*args和/或**kwargs作为函数定义参数列表中的最后一项,允许该函数接受任意数量的参数和/或关键字参数。

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

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

在面向对象编程中,当您重写一个函数,并且想要用用户传递的任何参数调用原始函数时,它可能更常用。

实际上,你不必称他们为argskwargs,这只是惯例。正是***创造了魔法。

官方的python文档有更深入的了解。


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

1
2
3
4
5
6
7
8
9
10
11
12
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 )

这样子类就不知道(或关心)什么是超类初始化。如果你意识到你需要改变超类,你可以在不必为每一个子类的细节操心的情况下解决问题。


注意S.lott的评论中的一个很酷的东西——您也可以调用带有*mylist**mydict的函数来解包位置和关键字参数:

1
2
3
4
5
6
7
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


*args**kwargs的另一个好用法是:您可以定义通用的"catch all"函数,这对于返回此类包装而不是原始函数的装饰器非常有用。

使用普通缓存装饰器的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

只是为了澄清如何解开这些论点,以及如何处理遗漏的论点等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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')